package com.xique.park.service.biz.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.PhoneUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xique.common.core.constant.Constants;
import com.xique.common.core.domain.R;
import com.xique.common.core.enums.MngTypeEnum;
import com.xique.common.core.utils.DateUtils;
import com.xique.common.core.utils.SecurityUtils;
import com.xique.common.core.utils.StringUtils;
import com.xique.common.core.utils.poi.ExcelUtil;
import com.xique.common.core.web.domain.AjaxResult;
import com.xique.common.core.web.domain.PageResult;
import com.xique.park.bean.domain.*;
import com.xique.park.bean.request.app.*;
import com.xique.park.bean.request.web.car.*;
import com.xique.park.bean.request.web.parkcar.ParkCarRequest;
import com.xique.park.bean.search.app.ParkCarListSearch;
import com.xique.park.bean.search.app.ParkPlateCheckSearch;
import com.xique.park.bean.transform.app.ParkCarTransform;
import com.xique.park.bean.vo.app.ParkCarCalFixedFeeVo;
import com.xique.park.bean.vo.app.ParkCarEditVo;
import com.xique.park.bean.vo.app.ParkCarFeeVo;
import com.xique.park.bean.vo.app.ParkCarVo;
import com.xique.park.bean.vo.comm.DuplicatePlateVo;
import com.xique.park.bean.vo.web.car.ParkCarDepositInfoVo;
import com.xique.park.bean.vo.web.car.ParkCarDetailVo;
import com.xique.park.constant.DictConstant;
import com.xique.park.mapper.ParkDepositLogMapper;
import com.xique.park.service.biz.service.*;
import com.xique.park.service.command.service.IParkCarCommandService;
import com.xique.park.service.service.*;
import com.xique.system.api.RemoteSystemProjectService;
import com.xique.system.api.RemoteSystemUserService;
import com.xique.system.api.dto.OperateDTO;
import com.xique.system.api.dto.SystemProjectDTO;
import com.xique.system.api.dto.SystemUserDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 车辆管理
 *
 * @author lxl
 */
@Service
@Slf4j
public class ParkCarBizServiceImpl implements IParkCarBizService {

    @Autowired
    private IParkCarService parkCarService;

    @Autowired
    private IParkUserBizService parkUserBizService;

    @Autowired
    private IParkCarMngtypeBizService parkCarMngtypeBizService;

    @Autowired
    private IParkCarMngtypeService parkCarMngtypeService;

    @Autowired
    private IParkCarCommandService parkCarCommandService;

    @Autowired
    private IPayOrderBizService payOrderBizService;

    @Autowired
    private IPayOrderService payOrderService;

    @Autowired
    private IParkOnBizService parkOnBizService;

    @Autowired
    private IParkGarageService parkGarageService;

    @Autowired
    private IParkGarageCarSpaceService parkGarageCarSpaceService;

    @Autowired
    private IParkConfigService parkConfigService;

    @Autowired
    private RemoteSystemUserService remoteSystemUserService;

    @Autowired
    private DataSourceTransactionManager dataSourceTransactionManager;

    @Autowired
    private TransactionDefinition transactionDefinition;

    @Autowired
    private IUserService userService;

    @Autowired
    private IBaseUserService baseUserService;

    @Autowired
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;

    @Autowired
    private ParkFeeLogService parkFeeLogService;

    @Autowired
    private ParkDepositLogMapper parkDepositLogMapper;

    @Autowired
    private ParkUpdateCarLogService parkUpdateCarLogService;

    @Autowired
    private RemoteSystemProjectService remoteSystemProjectService;

    @Autowired
    private IParkInfoService parkInfoService;

    @Autowired
    private IUserAndBaseUserBizService userAndBaseUserBizService;

    @Override
    public AjaxResult getParkCarList(ParkCarListRequest request) {
        Map<String, Object> map = new HashMap<>(2);
        ParkCarListSearch search = new ParkCarListSearch();
        search.setParkId(SecurityUtils.getParkId());
        search.setPlate(request.getPlate());
        search.setPageNum(request.getPageNum());
        search.setPageSize(request.getPageSize());
        search.setUserName(request.getUserName());
        search.setPhone(request.getPhone());
        search.setAddress(request.getAddress());
        search.setMngTypeId(request.getMngTypeId());
        search.setSeatNo(request.getSeatNo());
        search.setParam(request.getParam());
        IPage<ParkCar> page = parkCarService.selectParkCarPage(search);
        List<ParkCar> list = page.getRecords();
        // 记录同步状态处理
        List<Long> recIdList = list.stream().map(ParkCar::getId).collect(Collectors.toList());
        JSONObject commandStatusObj = parkCarCommandService.getCommandStatus(SecurityUtils.getParkId(), recIdList);

        List<ParkCarVo> vos = list.stream().map(item -> {
            User user = userService.selectUserById(item.getParkUserId());
            ParkCarVo vo = ParkCarTransform.transformParkCarVo(item, user);
            ParkCarMngtype parkCarMngtype = parkCarMngtypeService.selectParkCarMngtypeById(item.getMngTypeId());
            vo.setMngTypeName(null != parkCarMngtype ? parkCarMngtype.getName() : null);
            JSONObject commandResultObj = (JSONObject) commandStatusObj.get(item.getId());
            // 同步状态赋值
            vo.setCommandStatus(commandResultObj);
            return vo;
        }).collect(Collectors.toList());
        map.put("list", vos);
        map.put("total", page.getTotal());
        return AjaxResult.success(map);
    }

    @Override
    public AjaxResult getParkCarInfo(Long carId) {
        ParkCar parkCar = parkCarService.selectParkCarById(carId);
        if (null != parkCar) {
            User user = userService.selectUserById(parkCar.getParkUserId());
            ParkCarEditVo parkCarEditVo = ParkCarTransform.transformParkCarEditVo(parkCar, user);
            ParkCarMngtype parkCarMngtype = parkCarMngtypeService.selectParkCarMngtypeById(parkCar.getMngTypeId());
            parkCarEditVo.setMngTypeName(null != parkCarMngtype ? parkCarMngtype.getName() : null);
            return AjaxResult.success(parkCarEditVo);
        } else {
            return AjaxResult.error("未查询到车辆信息");
        }
    }

    /**
     * 1、查询车辆基本信息
     * 2、根据车辆管理类型，查询该类车的月金额(月金额*车位数)
     */
    @Override
    public AjaxResult getParkCarFeeInfo(Long carId) {
        ParkCar parkCar = parkCarService.selectParkCarById(carId);
        if (null != parkCar) {
            ParkCarFeeVo parkCarFeeVo = new ParkCarFeeVo();
            Long mngtypeId = parkCar.getMngTypeId();
            parkCarFeeVo.setMngType(parkCar.getMngType());
            if (null != mngtypeId) {
                ParkChargeCarFixed parkChargeCarFixed = parkCarMngtypeBizService.getParkChargeFixed(mngtypeId);
                Long monthFee = calFixedCarMonthFee(parkCar.getSpaces(), parkChargeCarFixed);
                parkCarFeeVo.setMonthFee(monthFee);
                ParkCarMngtype parkCarMngtype = parkCarMngtypeService.selectParkCarMngtypeById(mngtypeId);
                if (null != parkCarMngtype) {
                    parkCarFeeVo.setMngTypeName(parkCarMngtype.getName());
                    parkCarFeeVo.setMngTypeId(parkCarMngtype.getId());
                }
            }
            parkCarFeeVo.setCarId(parkCar.getId());
            parkCarFeeVo.setOriginalBeginDate(parkCar.getBeginDate());
            parkCarFeeVo.setOriginalEndDate(parkCar.getEndDate());
            parkCarFeeVo.setNewBeginDate(DateUtil.offsetDay(parkCar.getEndDate(), 1));
            parkCarFeeVo.setPlates(parkCar.getBindPlates());
            parkCarFeeVo.setSeatNo(parkCar.getSeatNo());
            parkCarFeeVo.setForeverStatus(parkCar.getForeverStatus());
            parkCarFeeVo.setSpaceNum(parkCar.getSpaces());
            User user = null != parkCar.getParkUserId() ? userService.selectUserById(parkCar.getParkUserId()) : null;
            parkCarFeeVo.setUserName(null != user ? user.getUserName() : null);
            return AjaxResult.success(parkCarFeeVo);
        } else {
            return AjaxResult.error("未查询到车辆信息");
        }
    }

    @Override
    public AjaxResult addParkCar(ParkCarAddRequest request) {
        // 手动开启事务
        TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);

        ParkCar parkCar = null;
        try {
            parkCar = ParkCarTransform.transformAddParkCar2ParkCar(request);
            /* 车牌校验 */
            ParkPlateCheckSearch search = new ParkPlateCheckSearch();
            search.setParkId(SecurityUtils.getParkId());
            search.setPlates(request.getPlates());
            Map<String, Object> plateCheckMap = checkPlateUnique(search);
            if (null != plateCheckMap && !(Boolean) plateCheckMap.get("isUnique")) {
                // 回滚
                dataSourceTransactionManager.rollback(transactionStatus);
                return AjaxResult.error("车牌号已被绑定", plateCheckMap);
            }

            // 校验手机号重复
            if (!StringUtils.isEmpty(request.getPhone()) && request.getUserId() == null) {
                User user = new User();
                user.setParkId(SecurityUtils.getParkId());
                user.setPhone(request.getPhone());
                user.setDelFlag(0);
                List<User> users = userService.selectUserList(user);
                if (!users.isEmpty()) {
                    dataSourceTransactionManager.rollback(transactionStatus);
                    return AjaxResult.error("手机号已存在！");
                }
            }

            /* 车主信息处理 */
            Long parkUserId = parkUserBizService.addCarParkUserHandle(request, SecurityUtils.getParkId());
            parkCar.setParkUserId(parkUserId);
            parkCarService.insertParkCar(parkCar);
            if (!MngTypeEnum.BLACKLIST.getType().equals(parkCar.getMngType())) {
                /* 生成月卡车续费记录 */
                payOrderBizService.generateFixedCarPayOrder(request, parkCar);
            }
            // 提交
            dataSourceTransactionManager.commit(transactionStatus);
        } catch (Exception e) {
            e.printStackTrace();
            // 回滚
            dataSourceTransactionManager.rollback(transactionStatus);
            return AjaxResult.error("保存失败，" + e.getMessage());
        }
        return parkCarCommandService.downSingleCar(SecurityUtils.getParkId(), parkCar, "保存成功！");
    }

    @Override
    public AjaxResult editParkCar(ParkCarEditRequest request) {
        // 手动开启事务
        TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);

        ParkCar parkCar = null;
        try {
            ParkCar originalCar = parkCarService.selectParkCarById(request.getCarId());
            parkCar = ParkCarTransform.transformEditParkCar2ParkCar(request, originalCar);
            /*车牌校验*/
            ParkPlateCheckSearch search = new ParkPlateCheckSearch();
            search.setParkId(SecurityUtils.getParkId());
            search.setPlates(request.getPlates());
            search.setCarId(request.getCarId());
            Map<String, Object> plateCheckMap = checkPlateUnique(search);
            if (null != plateCheckMap && !(Boolean) plateCheckMap.get("isUnique")) {
                // 回滚
                dataSourceTransactionManager.rollback(transactionStatus);
                return AjaxResult.error("车牌号已被绑定", plateCheckMap);
            }
            /* 车主信息处理 */
            Long parkUserId = parkUserBizService.editCarParkUserHandle(request, SecurityUtils.getParkId());
            parkCar.setParkUserId(parkUserId);
            parkCar.setUpdateTime(new Date());
            parkCar.setUpdateUser(SecurityUtils.getUserId());
            parkCarService.updateParkCar(parkCar);
            // 提交
            dataSourceTransactionManager.commit(transactionStatus);
        } catch (Exception e) {
            e.printStackTrace();
            // 回滚
            dataSourceTransactionManager.rollback(transactionStatus);
            return AjaxResult.error("保存失败，" + e.getMessage());
        }
        /* 下发到设备 */
        return parkCarCommandService.downSingleCar(SecurityUtils.getParkId(), parkCar, "保存成功！");
    }

    @Override
    public AjaxResult feeParkCar(ParkCarFeeRequest request) {
        // 手动开启事务
        TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
        ParkCar newCar;
        try {
            ParkCar parkCar = parkCarService.selectParkCarById(request.getCarId());
            // 此次续费的有效期开始日期(车辆上次截至日期)
            Date beginDate = parkCar.getEndDate();
            newCar = ParkCarTransform.transformFeeParkCar2ParkCar(request, parkCar);
            newCar.setUpdateTime(new Date());
            newCar.setUpdateUser(SecurityUtils.getUserId());

            // 判断是否永久
            if (null != request.getForeverStatus() && request.getForeverStatus()) {
                newCar.setEndDate(DateUtil.parseDate(Constants.FOREVER_TIME));
                newCar.setForeverStatus(request.getForeverStatus());
            }

            int count = parkCarService.updateParkCar(newCar);
            if (0 < count) {
                // 生成月卡车续费记录
                payOrderBizService.generateFixedCarPayOrder(request, newCar, beginDate);
                //生成续费记录
                if (!insertFeeLog(request, parkCar)) {
                    return AjaxResult.error("生成续费记录失败");
                }
                // 提交
                dataSourceTransactionManager.commit(transactionStatus);
            } else {
                // 回滚
                dataSourceTransactionManager.rollback(transactionStatus);
                return AjaxResult.error("保存失败");
            }
        } catch (Exception e) {
            e.printStackTrace();
            // 回滚
            dataSourceTransactionManager.rollback(transactionStatus);
            return AjaxResult.error("保存失败");
        }
        // 下发到设备
        return parkCarCommandService.downSingleCar(SecurityUtils.getParkId(), newCar, "保存成功！");
    }

    /**
     * 单体插入续费日志记录
     */
    private boolean insertFeeLog(ParkCarFeeRequest request, ParkCar parkCar) {
        String cysNum = "";
        int days = DateUtils.differentDaysByMillisecond(request.getNewBeginDate(), request.getEndDate());
        if (days < 30) {
            cysNum = request.getInputDate() + "天";
        } else if (days < 365) {
            cysNum = request.getInputDate() + "个月";
        } else {
            cysNum = request.getInputDate() + "年";
        }
        ParkFeeLog log = ParkFeeLog.builder().parkId(parkCar.getParkId())
                .carId(request.getCarId())
                .updateTime(new Date())
                .operId(SecurityUtils.getUserId())
                .operName(SecurityUtils.getUsername())
                .updateType(1)
                .originalBeginDate(parkCar.getBeginDate())
                .originalEndDate(parkCar.getEndDate())
                .newBeginDate(request.getNewBeginDate())
                .newEndDate(request.getEndDate())
                .fee(request.getFee()).actualFee(request.getActualFee()).payType(request.getPayType())
                .cysNum(cysNum)
                .plate(parkCar.getPlate())
                .phone(StringUtils.isNotNull(parkCar.getPhone()) ? parkCar.getPhone() : null)
                .userName(parkCar.getUserName())
                .build();
        return parkFeeLogService.save(log);
    }


    @Override
    public AjaxResult delParkCar(ParkCarDeleteRequest request) {
        Long carId = request.getCarId();
        ParkCar parkCar = parkCarService.selectParkCarById(carId);
        // 下发到设备
        parkUpdateCarLogService.generateDelLog(request, parkCar);
        return parkCarCommandService.delSingleCar(SecurityUtils.getParkId(), parkCar, "删除中！");
    }

    /**
     * 1、先看按月收费是否为空，不为空，则取该值；如果为空，则看按日收费，如果不为空，则乘以30算每月，如果也为空，则每月为0；
     */
    @Override
    public Long calFixedCarMonthFee(Integer spaceCnt, ParkChargeCarFixed parkChargeCarFixed) {
        spaceCnt = null != spaceCnt ? spaceCnt : 1;
        if (null != parkChargeCarFixed) {
            Long monthCharge = (null != parkChargeCarFixed.getMonthCharge()) ? parkChargeCarFixed.getMonthCharge()
                    : (null != parkChargeCarFixed.getDayCharge() ? parkChargeCarFixed.getDayCharge() * 30 : 0);
            return spaceCnt * monthCharge;
        } else {
            return 0L;
        }
    }

    /**
     * false表示不唯一，true表示唯一
     */
    @Override
    public AjaxResult checkPlateUnique(ParkCarUniqueCheckRequest request) {
        long carId = StringUtils.isNull(request.getCarId()) ? -1L : request.getCarId();
        ParkCar search = new ParkCar();
        search.setParkId(SecurityUtils.getParkId());
        search.setId(carId);
        search.setPlate(request.getPlate());
        ParkCar parkCar = parkCarService.checkParkPlateUnique(search);
        if (StringUtils.isNotNull(parkCar)) {
            if (parkCar.getId() != carId) {
                return AjaxResult.error("车牌号已存在");
            } else {
                return AjaxResult.success("车牌号校验通过");
            }
        } else {
            return AjaxResult.success("车牌号校验通过");
        }
    }

    /**
     * {
     * "isUnique":false,
     * "duplicatePlates":[
     * "plate1",
     * "plate2"
     * ]
     * }
     */
    @Override
    public Map<String, Object> checkPlateUnique(ParkPlateCheckSearch search) {
        Map<String, Object> map = new HashMap<>(2);
        map.put("isUnique", true);
        String plates = search.getPlates();
        List<String> duplicatePlates = new ArrayList<>();
        List<DuplicatePlateVo> duplicatePlateVos = new ArrayList<>();
        if (StringUtils.isNotEmpty(plates)) {
            String[] plateArr = plates.split(",");
            ParkCar searchCar = new ParkCar();
            searchCar.setParkId(search.getParkId());
            searchCar.setId(search.getCarId());
            for (String plate : plateArr) {
                searchCar.setPlate(plate);
                ParkCar parkCar = parkCarService.checkParkPlateUnique(searchCar);
                if (StringUtils.isNotNull(parkCar)) {
                    if (null == search.getCarId() || (null != search.getCarId() && parkCar.getId().longValue() != search.getCarId())) {
                        duplicatePlates.add(plate);
                        //冠友新增返回字段
                        DuplicatePlateVo duplicatePlateVo = new DuplicatePlateVo();
                        duplicatePlateVo.setDuplicatePlate(plate);
                        duplicatePlateVo.setCarId(parkCar.getId());
                        duplicatePlateVo.setUserId(parkCar.getParkUserId());
                        duplicatePlateVos.add(duplicatePlateVo);
                    }
                }
            }
        }
        if (!CollectionUtils.isEmpty(duplicatePlates)) {
            map.put("isUnique", false);
            map.put("duplicatePlates", duplicatePlates);
            map.put("duplicatePlateVos", duplicatePlateVos);
        }
        return map;
    }

    @Override
    public AjaxResult calFixedFee(ParkCarCalFixedFeeRequest request) {
        ParkChargeCarFixed parkChargeCarFixed = parkCarMngtypeBizService.getParkChargeFixed(request.getMngTypeId());
        ParkCarCalFixedFeeVo vo = new ParkCarCalFixedFeeVo();
        if (StringUtils.isNull(parkChargeCarFixed)) {
            vo.setMayFee(0L);
            return AjaxResult.success(vo);
        }

        String cycle = request.getCycle();
        Integer spaceNum = request.getSpaceNum();
        if (StringUtils.isEmpty(cycle)) {
            Long monthFee = calFixedCarMonthFee(1, parkChargeCarFixed);
            long months = DateUtil.betweenMonth(request.getBeginDate(), request.getEndDate(), true);
            Long fee = monthFee * months * spaceNum;
            vo.setMayFee(fee);
        } else {
            int cycleNum = request.getCycleNum();
            long cycleFee = 0L;
            if ("year".equals(cycle)) {
                cycleFee = StringUtils.isNotNull(parkChargeCarFixed.getYearCharge()) ? parkChargeCarFixed.getYearCharge() : 0L;

            } else if ("month".equals(cycle)) {
                cycleFee = StringUtils.isNotNull(parkChargeCarFixed.getMonthCharge()) ? parkChargeCarFixed.getMonthCharge() : 0L;
            } else if ("day".equals(cycle)) {
                cycleFee = StringUtils.isNotNull(parkChargeCarFixed.getDayCharge()) ? parkChargeCarFixed.getDayCharge() : 0L;
            }
            vo.setMayFee(cycleNum * cycleFee * spaceNum);
        }
        return AjaxResult.success(vo);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @SuppressWarnings("unchecked")
    public AjaxResult getWebParkCarList(ParkCarRequest request) {
        PageResult pageResult = parkCarService.selectPageList(request);
        List<ParkCarVo> parkCarVoList = (List<ParkCarVo>) pageResult.getList();

        // 记录同步状态处理
        List<Long> recIdList = parkCarVoList.stream().map(ParkCarVo::getId).collect(Collectors.toList());
        JSONObject commandStatusObj = parkCarCommandService.getCommandStatus(request.getParkId(), recIdList);

        StringBuilder operateIds = new StringBuilder();
        parkCarVoList.forEach(carVo -> {
            // 车主信息有，但是没有保存到用户表的处理
            if (null == carVo.getParkUserId() && StringUtils.isNotEmpty(carVo.getUserName())) {
                ParkCar parkCar = new ParkCar();
                BeanUtils.copyProperties(carVo, parkCar);
                parkUserBizService.parkUserHandle(parkCar);
            }

            JSONObject commandResultObj = (JSONObject) commandStatusObj.get(carVo.getId());
            // 同步状态赋值
            carVo.setCommandStatus(commandResultObj);

            Long updateUserId = carVo.getUpdateUser();
            if (null != updateUserId) {
                operateIds.append(updateUserId).append(",");
            }
        });

        // 赋值操作人信息
        if (StrUtil.isNotBlank(operateIds)) {
            R<List<OperateDTO>> result = remoteSystemUserService.getOperateList(operateIds.toString());
            if (result.getData() != null) {
                List<OperateDTO> operateDTOList = result.getData();
                if (CollUtil.isNotEmpty(operateDTOList)) {
                    Map<Long, String> operateMap = operateDTOList.stream().collect(Collectors.toMap(OperateDTO::getOperateId, OperateDTO::getOperateName));
                    parkCarVoList.forEach(parkCarVo -> parkCarVo.setUpdateBy(operateMap.get(parkCarVo.getUpdateUser())));
                }
            }
        }

        Map<String, Object> map = new HashMap<>(3);
        map.put("list", parkCarVoList);
        map.put("total", pageResult.getTotalPages());
        map.put("totalSize", pageResult.getTotalSize());
        return AjaxResult.success(map);
    }

    /**
     * web端保存车辆
     */
    @Override
    public AjaxResult addWebParkCar(ParkCarAddRequest request) {
        // 手动开启事务
        TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);

        ParkCar parkCar;
        try {
            parkCar = ParkCarTransform.transformAddParkCar2ParkCar(request);
            /* 车牌校验 */
            ParkPlateCheckSearch search = new ParkPlateCheckSearch();
            search.setParkId(request.getParkId());
            search.setPlates(request.getPlates());
            Map<String, Object> plateCheckMap = checkPlateUnique(search);
            if (null != plateCheckMap && !(Boolean) plateCheckMap.get("isUnique")) {
                // 回滚事务
                dataSourceTransactionManager.rollback(transactionStatus);
                return AjaxResult.error("车牌号已被绑定", plateCheckMap);
            }
            // 新增用户
            if (null == request.getUserId() && StringUtils.isNotEmpty(request.getPhone())) {
                List<User> users = userService.selectUserByPhone(SecurityUtils.getParkId(), request.getPhone());
                if (CollUtil.isNotEmpty(users)) {
                    // 回滚事务
                    dataSourceTransactionManager.rollback(transactionStatus);
                    return AjaxResult.error("手机号：" + request.getPhone() + ",已存在用户，请使用【选择用户】功能");
                }
            }
            // 车主信息处理
            Long parkUserId = parkUserBizService.addWebCarParkUserHandle(request, request.getParkId());
            parkCar.setParkUserId(parkUserId);
            parkCar.setUpdateTime(new Date());
            parkCar.setUpdateUser(SecurityUtils.getUserId() != null ? SecurityUtils.getUserId() : 1);

            if (CollUtil.isNotEmpty(request.getSpaceList())) {
                StringBuilder seatNo = new StringBuilder();
                StringBuilder garageIds = new StringBuilder();
                request.getSpaceList().forEach(parkCarAddGarageSpaceRequest -> {
                    if (StringUtils.isNotEmpty(parkCarAddGarageSpaceRequest.getSeatNo())) {
                        seatNo.append(parkCarAddGarageSpaceRequest.getSeatNo());
                        seatNo.append(",");

                        garageIds.append(parkCarAddGarageSpaceRequest.getGarageId());
                        garageIds.append(",");
                    }
                });
                int index = seatNo.lastIndexOf(",");
                if (index != -1) {
                    parkCar.setSeatNo(seatNo.substring(0, index));
                }

                // 设置车库ID
                parkCar.setGarageIds(garageIds.toString());

                long spaces = request.getSpaceList().stream().mapToLong(parkCarAddGarageSpaceRequest -> {
                    if (null != parkCarAddGarageSpaceRequest.getSpaceCnt()) {
                        return parkCarAddGarageSpaceRequest.getSpaceCnt();
                    } else {
                        return 1;
                    }
                }).sum();
                parkCar.setSpaces((int) spaces);
            }

            if ((null != request.getForeverStatus() && request.getForeverStatus()) || StrUtil.equals(request.getMngType(), MngTypeEnum.FREE.getType())) {
                parkCar.setBeginDate(new Date());
                parkCar.setEndDate(DateUtil.parseDate(Constants.FOREVER_TIME));
                parkCar.setForeverStatus(request.getForeverStatus());
            } else {
                parkCar.setForeverStatus(Boolean.FALSE);
                if (parkCar.getBeginDate() == null || parkCar.getEndDate() == null) {
                    // 回滚事务
                    dataSourceTransactionManager.rollback(transactionStatus);
                    throw new IllegalArgumentException("期限为非永久时，起始日期和截止日期必填");
                }
            }

            int count = parkCarService.insertParkCar(parkCar);
            if (0 < count) {
                if (request.getIsGarageSpace().equals(Constants.YES)) {
                    // 多车库的多位多车处理
                    garageSpacesHandle(request.getIsGarageSpace(), parkCar.getId(), request.getSpaceList());
                }
                if (!MngTypeEnum.BLACKLIST.getType().equals(parkCar.getMngType())) {
                    // 生成月卡车续费记录
                    payOrderBizService.generateFixedCarPayOrder(request, parkCar);
                }
                //车辆生成记录
                parkUpdateCarLogService.generateAddParkLog(request, parkCar);
                // 提交
                dataSourceTransactionManager.commit(transactionStatus);
            } else {
                // 回滚
                dataSourceTransactionManager.rollback(transactionStatus);
                throw new IllegalArgumentException("车辆信息保存失败");
            }
        } catch (Exception e) {
            e.printStackTrace();
            // 回滚
            dataSourceTransactionManager.rollback(transactionStatus);
            return AjaxResult.error("保存失败，" + e.getMessage());
        }

        // 下发到设备
        AjaxResult downResult = parkCarCommandService.downSingleCar(request.getParkId(), parkCar, "保存成功！");
        Map<String, Object> data = new HashMap<>(1);
        downResult.put(AjaxResult.DATA_TAG, data);
        data.put("carId", parkCar.getId());
        data.put("userId", parkCar.getParkUserId());
        return downResult;
    }

    /**
     * web端编辑车辆
     */
    @Override
    public AjaxResult editWebParkCar(ParkCarEditRequest request) {
        // 手动开启事务
        TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
        ParkCar parkCar;
        try {
            ParkCar originalCar = parkCarService.selectParkCarById(request.getCarId());
            Integer spacesNo = originalCar.getSpaces();
            Long mngTypeId = originalCar.getMngTypeId();
            if (originalCar == null) {
                dataSourceTransactionManager.rollback(transactionStatus);
                return AjaxResult.error("车辆不存在");
            }
            parkCar = ParkCarTransform.transformEditParkCar2ParkCar(request, originalCar);
            // 车牌校验
            ParkPlateCheckSearch search = new ParkPlateCheckSearch();
            search.setParkId(SecurityUtils.getParkId());
            search.setPlates(request.getPlates());
            search.setCarId(request.getCarId());
            Map<String, Object> plateCheckMap = checkPlateUnique(search);
            if (null != plateCheckMap && !(Boolean) plateCheckMap.get("isUnique")) {
                // 回滚
                dataSourceTransactionManager.rollback(transactionStatus);
                return AjaxResult.error("车牌号已被绑定", plateCheckMap);
            }

            // 车主信息处理
            Long parkUserId = parkUserBizService.editWebCarParkUserHandle(request, request.getParkId());
            parkCar.setParkUserId(parkUserId);
            parkCar.setUserName(request.getUserName());
            parkCar.setPhone(request.getPhone());
            parkCar.setAddress(request.getAddress());
            parkCar.setUpdateTime(new Date());
            parkCar.setUpdateUser(SecurityUtils.getUserId() != null ? SecurityUtils.getUserId() : 1);

            if (CollUtil.isNotEmpty(request.getSpaceList())) {
                StringBuilder seatNo = new StringBuilder();
                StringBuilder garageIds = new StringBuilder();
                request.getSpaceList().forEach(parkCarAddGarageSpaceRequest -> {
                    if (StringUtils.isNotEmpty(parkCarAddGarageSpaceRequest.getSeatNo())) {
                        seatNo.append(parkCarAddGarageSpaceRequest.getSeatNo());
                        seatNo.append(",");

                        garageIds.append(parkCarAddGarageSpaceRequest.getGarageId());
                        garageIds.append(",");
                    }
                });
                int index = seatNo.lastIndexOf(",");
                if (index != -1) {
                    parkCar.setSeatNo(seatNo.substring(0, index));
                }

                parkCar.setGarageIds(garageIds.toString());

                long spaces = request.getSpaceList().stream().mapToLong(parkCarAddGarageSpaceRequest -> {
                    if (null != parkCarAddGarageSpaceRequest.getSpaceCnt()) {
                        return parkCarAddGarageSpaceRequest.getSpaceCnt();
                    } else {
                        return 1;
                    }
                }).sum();
                parkCar.setSpaces((int) spaces);
            }

            if ((null != request.getForeverStatus() && request.getForeverStatus()) || StrUtil.equals(request.getMngType(), MngTypeEnum.FREE.getType())) {
                parkCar.setBeginDate(new Date());
                parkCar.setEndDate(DateUtil.parseDate(Constants.FOREVER_TIME));
                parkCar.setForeverStatus(request.getForeverStatus());
            } else {
                parkCar.setForeverStatus(Boolean.FALSE);
                if (parkCar.getBeginDate() == null || parkCar.getEndDate() == null) {
                    // 回滚
                    dataSourceTransactionManager.rollback(transactionStatus);
                    throw new IllegalArgumentException("期限为非永久时，起始日期和截止日期必填");
                }
            }
            int count = parkCarService.updateParkCar(parkCar);
            if (0 < count) {
                if (request.getIsGarageSpace().equals(Constants.YES)) {
                    // 多车库的多位多车处理
                    garageSpacesHandle(request.getIsGarageSpace(), parkCar.getId(), request.getSpaceList());
                }

                parkUpdateCarLogService.generateUpdateLog(request, originalCar, spacesNo, mngTypeId);
                // 提交
                dataSourceTransactionManager.commit(transactionStatus);
            } else {
                // 回滚
                dataSourceTransactionManager.rollback(transactionStatus);
                throw new IllegalArgumentException("车辆信息保存失败");
            }


        } catch (Exception e) {
            e.printStackTrace();
            // 回滚
            dataSourceTransactionManager.rollback(transactionStatus);
            return AjaxResult.error("保存失败，" + e.getMessage());
        }
        // 下发到设备
        return parkCarCommandService.downSingleCar(request.getParkId(), parkCar, "保存成功！");
    }


    /**
     * 批量续费
     * 1、批量修改车辆的截至日期（注意月为周期月初和月末的处理）
     * 2、批量生成车辆的续费记录
     * 3、下发到设备
     */
    @Override
    public AjaxResult batchFeeParkCar(ParkCarBatchFeeRequest request) {
        Long[] carIds = request.getCarIds();
        List<ParkCar> carList;
        if (carIds.length > 0) {
            carList = parkCarService.selectBatchIds(Arrays.asList(carIds));
        } else {
            return AjaxResult.error("请至少选中一条记录");
        }

        if (CollectionUtils.isEmpty(carList)) {
            return AjaxResult.error("操作失败。记录不存在");
        }

        for (ParkCar car : carList) {
            // 1、车辆处理
            if ("day".equals(request.getCycleType())) {
                Date newEndDate = DateUtils.getNextDate(car.getEndDate(), request.getValue());
                String newEndDateStr = DateUtil.format(newEndDate, DatePattern.NORM_DATE_PATTERN) + " 23:59:59";
                car.setEndDate(DateUtil.parseDateTime(newEndDateStr));
            }
            if ("month".equals(request.getCycleType())) {
                Date newEndDate = DateUtils.getMonthDate(car.getEndDate(), request.getValue());
                String newEndDateStr = DateUtil.format(newEndDate, DatePattern.NORM_DATE_PATTERN) + " 23:59:59";
                car.setEndDate(DateUtil.parseDateTime(newEndDateStr));
            }
            car.setUpdateUser(SecurityUtils.getUserId());
            car.setUpdateTime(new Date());
            car.setRemark(request.getRemark());
        }
        // 手动开启事务！
        TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
        int count;
        try {
            count = parkCarService.batchUpdate(carList);
            if (count > 0) {
                // 2、续费记录
                PayOrder payOrder = payOrderBizService.generatePayOrderFromCar(request, carList);
                payOrderService.insertTPayOrder(payOrder);
            }
            // 提交
            dataSourceTransactionManager.commit(transactionStatus);
        } catch (Exception e) {
            e.printStackTrace();
            // 回滚
            dataSourceTransactionManager.rollback(transactionStatus);
            return AjaxResult.error("保存失败", e.getMessage());
        }
        return parkCarCommandService.downCars(SecurityUtils.getParkId(), carList, "车辆续费成功！");
    }

    @Override
    public AjaxResult batchDeleteParkCar(ParkCarBatchDeleteRequest request) {
        Long[] carIds = request.getCarIds();
        if (carIds.length > 0) {
            List<ParkCar> list = parkCarService.selectBatchIds(Arrays.asList(carIds));
            // 下发删除车辆命令
            parkUpdateCarLogService.generateBatchDelLog(list);
            return parkCarCommandService.delCars(SecurityUtils.getParkId(), list, "删除中！");
        } else {
            return AjaxResult.error("请至少选中一条记录");
        }
    }

    @Override
    public AjaxResult getParkCarDetailInfo(Long carId) {
        ParkCar parkCar = parkCarService.selectParkCarById(carId);
        if (null != parkCar) {
            User user = userService.selectUserById(parkCar.getParkUserId());
            ParkCarDetailVo parkCarDetailVo = ParkCarTransform.transformParkCarDetailVo(parkCar, user);
            ParkCarMngtype parkCarMngtype = parkCarMngtypeService.selectParkCarMngtypeById(parkCar.getMngTypeId());
            parkCarDetailVo.setMngTypeName(null != parkCarMngtype ? parkCarMngtype.getName() : null);
            parkCarDetailVo.setSpaceList(getCarGarageSpacesList(carId));

            // 查询操作人信息
            R<OperateDTO> oprResult = remoteSystemUserService.getOperate(parkCarDetailVo.getUpdateUserId());
            if (oprResult.getData() != null) {
                parkCarDetailVo.setUpdateBy(oprResult.getData().getOperateName());
            }

            parkCarDetailVo.setEnGarageSpace(parkConfigService.getEnGarageSpaces());

            return AjaxResult.success(parkCarDetailVo);
        } else {
            return AjaxResult.error("未查询到车辆信息");
        }
    }

    /**
     * 下发车辆信息
     *
     * @return 是否下发成功
     */
    private AjaxResult downSingleCar(Long parkId, List<ParkCar> parkCarList) {
        AjaxResult result;
        if (CollUtil.isNotEmpty(parkCarList)) {
            // 下发到设备
            result = parkCarCommandService.downCars(parkId, parkCarList, "");
        } else {
            result = AjaxResult.success("车辆列表为空，无需下发");
        }
        return result;
    }

    /**
     * 判断车库是否启用了分车库统计
     *
     * @param parkId 车场ID
     * @return 是否启用了分车库统计 Y：是，N：否
     */
    private String enGarageSpaces(Long parkId) {
        long startTime = System.currentTimeMillis();
        ParkConfig parkConfig = parkConfigService.selectParkConfigByParkId(parkId);
        if (null == parkConfig) {
            throw new IllegalArgumentException("车场参数查询失败");
        }
        String jsonConfig = parkConfig.getConfig();
        String enGarageSpaces = "N";
        if (StrUtil.isNotEmpty(jsonConfig)) {
            JSONObject configJsonObject = JSON.parseObject(jsonConfig);
            enGarageSpaces = configJsonObject.getString("enGarageSpaces");
        }
        log.info("[车辆服务]-车辆导入：判断车库是否启用了分车库统计耗时：{}秒", (System.currentTimeMillis() - startTime) / 1000);
        return enGarageSpaces;
    }

    /**
     * 车辆储值
     * 1、保存车辆；
     * 2、生成车辆储值记录；
     * 3、是否需要下发到设备？
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public AjaxResult deposit(ParkCarDepositRequest request) {
        String remark = request.getRemark();
        Long balance = null != request.getBalance() ? request.getBalance() : 0L;
        Long deposit = null != request.getDeposit() ? request.getDeposit() : 0L;
        ParkCar parkCar = parkCarService.selectParkCarById(request.getCarId());

        if (StringUtils.isNotNull(parkCar)) {

            if (!insertDepositLog(request, parkCar)) {
                return AjaxResult.error("储值记录生成失败！");
            }
            parkCar.setBalance(balance + deposit);
            parkCar.setIsVal(Constants.YES);
            parkCar.setUpdateTime(DateUtils.getNowDate());
            parkCar.setUpdateUser(SecurityUtils.getUserId());
            parkCar.setUpdateTime(DateUtils.getNowDate());
            int count = parkCarService.updateParkCar(parkCar);
            if (count > 0) {
                PayOrder order = new PayOrder();
                order.setParkId(parkCar.getParkId());
                order.setPaySsn(System.currentTimeMillis() + "-" + parkCar.getParkId() + parkCar.getPlate());
                order.setPlate(parkCar.getBindPlates());
                order.setOrderIds(parkCar.getId() + "");
                order.setAmt(deposit);
                order.setActualFee(deposit);
                order.setPayTime(DateUtils.getNowDate());
                // 2=余额充值
                order.setTransType("2");
                order.setPayType(request.getPayType());
                order.setStatus("2");
                order.setRemark(StringUtils.isNotEmpty(remark) ? remark : "车牌【" + parkCar.getBindPlates() + "】储值" + deposit / 100 + "元");
                order.setCreateTime(DateUtils.getNowDate());
                order.setUpdateTime(DateUtils.getNowDate());
                order.setCreateUser(SecurityUtils.getUserId());
                order.setUpdateUser(SecurityUtils.getUserId());
                order.setPayChannel(getPayChannel(parkCar.getParkId()));
                payOrderService.insertTPayOrder(order);
                return AjaxResult.success("操作成功");
            } else {
                return AjaxResult.error("操作失败");
            }
        } else {
            return AjaxResult.error("操作失败！未查询到车辆信息");
        }
    }

    private String getPayChannel(Long parkId) {
        R<SystemProjectDTO> systemProjectR = remoteSystemProjectService.getProjectInfo(parkId);
        if (null != systemProjectR && null != systemProjectR.getData()) {
            SystemProjectDTO systemProject = systemProjectR.getData();
            return systemProject.getPayChannel();
        }
        return "";
    }

    /**
     * 插入储值记录
     */
    private boolean insertDepositLog(ParkCarDepositRequest request, ParkCar parkCar) {
        Long userId = SecurityUtils.getUserId();
        String username = SecurityUtils.getUsername();
        ParkDepositLog parkDepositLog = new ParkDepositLog();
        parkDepositLog.setCarId(request.getCarId());
        parkDepositLog.setBalance(request.getBalance());
        parkDepositLog.setDeposit(request.getDeposit());
        parkDepositLog.setPayType(request.getPayType());
        parkDepositLog.setRemark(request.getRemark());
        parkDepositLog.setPhone(parkCar.getPhone());
        parkDepositLog.setParkId(parkCar.getParkId());
        parkDepositLog.setPlate(parkCar.getPlate());
        parkDepositLog.setUserName(parkCar.getUserName());
        parkDepositLog.setOperId(userId);
        parkDepositLog.setUpdateTime(new Date());
        parkDepositLog.setOperName(username);
        return parkDepositLogMapper.insert(parkDepositLog) > 0;
    }

    @Override
    public AjaxResult downOne(ParkCarDownRequest request) {
        if (StringUtils.isNotNull(request.getCarId())) {
            ParkCar parkCar = parkCarService.selectParkCarById(request.getCarId());
            if (StringUtils.isNotNull(parkCar)) {
                return parkCarCommandService.downSingleCar(SecurityUtils.getParkId(), parkCar, "");
            } else {
                return AjaxResult.error("操作失败！未查询到车辆信息");
            }
        } else {
            return AjaxResult.error("ID不能为空");
        }
    }

    @Override
    public AjaxResult batchDown(ParkCarDownRequest request) {
        if (StringUtils.isNotNull(request.getCarIds())) {
            List<ParkCar> list = parkCarService.selectBatchIds(Arrays.asList(request.getCarIds()));
            if (CollectionUtils.isNotEmpty(list)) {
                return parkCarCommandService.downCars(SecurityUtils.getParkId(), list, "");
            } else {
                return AjaxResult.error("操作失败！未查询到车辆信息");
            }
        } else {
            return AjaxResult.error("请至少选中一条记录");
        }
    }

    @Override
    public AjaxResult downAll() {
        ParkCar parkCar = new ParkCar();
        parkCar.setParkId(SecurityUtils.getParkId());
        List<ParkCar> list = parkCarService.selectParkCarList(parkCar);
        if (CollectionUtils.isNotEmpty(list)) {
            return parkCarCommandService.downCars(SecurityUtils.getParkId(), list, "");
        } else {
            return AjaxResult.error("未查询到车辆信息");
        }
    }

    @Override
    public AjaxResult pauseParkCar(ParkCarPauseRequest request) {
        ParkCar parkCar = parkCarService.selectParkCarById(request.getCarId());
        if (null != parkCar) {
            parkCar.setStatus(DictConstant.STATUS_PAUSE);
            int count = parkCarService.updateParkCar(parkCar);
            if (0 < count) {
                // 下发到设备
                return parkCarCommandService.downSingleCar(SecurityUtils.getParkId(), parkCar, "保存成功！");
            } else {
                return AjaxResult.error("操作失败");
            }
        } else {
            return AjaxResult.error("操作失败！未查询到记录");
        }

    }

    @Override
    public AjaxResult getParkCarFeeList(ParkCarFeeListRequest request) {
        ParkCar parkCar = parkCarService.selectParkCarById(request.getCarId());
        if (null != parkCar) {
            PayOrder payOrder = new PayOrder();
            payOrder.setParkId(SecurityUtils.getParkId());
            payOrder.setTransType("1");
            payOrder.setPlate(parkCar.getPlate());
            List<PayOrder> list = payOrderService.selectTPayOrderList(payOrder);
            Map<String, Object> map = new HashMap<>();
            map.put("list", list);
            return AjaxResult.success(map);
        } else {
            return AjaxResult.error("操作失败！未查询到记录");
        }
    }

    /**
     * 查询车辆在场状态
     */
    @Override
    public AjaxResult getOnStatus(ParkCarOnStatusRequest request) {
        ParkCar parkCar = parkCarService.selectParkCarById(request.getCarId());
        if (null != parkCar) {
            String bindPlates = parkCar.getBindPlates();
            if (StringUtils.isNotEmpty(bindPlates)) {
                return AjaxResult.error("车牌号码不允许为空");
            } else {
                List<String> plateArr = Arrays.asList(bindPlates.split(","));
                return parkOnBizService.getOnStatus(SecurityUtils.getParkId(), plateArr);
            }
        } else {
            return AjaxResult.error("车辆不存在");
        }
    }

    @Override
    public AjaxResult getParkCarDepositInfo(Long carId) {
        ParkCar parkCar = parkCarService.selectParkCarById(carId);
        if (null != parkCar) {
            ParkCarDepositInfoVo depositInfoVo = new ParkCarDepositInfoVo();
            depositInfoVo.setCarId(parkCar.getId());
            //获取车主名称
            Long parkUserId = parkCar.getParkUserId();
            if (parkUserId != null) {
                User user = userService.selectUserById(parkUserId);
                if (user != null) {
                    depositInfoVo.setUserName(user.getUserName());
                }
            }
            depositInfoVo.setPlates(parkCar.getBindPlates());
            depositInfoVo.setBalance(null != parkCar.getBalance() ? parkCar.getBalance() : 0L);
            return AjaxResult.success(depositInfoVo);
        } else {
            return AjaxResult.error("未查询到车辆信息");
        }
    }

    /**
     * web
     */
    @Override
    public AjaxResult getWebParkCarInfo(Long carId) {
        ParkCar parkCar = parkCarService.selectParkCarById(carId);
        if (null == parkCar) {
            return AjaxResult.error("未查询到车辆信息");
        }
//        BaseUser baseUser = new BaseUser();
//        if (null != parkCar.getParkUserId()) {
//            baseUser = parkUserBizService.getParkUser(parkCar.getParkUserId());
//        } else {
//            // 车主信息有，但是没有保存到用户表的处理
//            if (StringUtils.isNotEmpty(parkCar.getUserName())) {
//                ParkUserDTO parkUserDTO = parkUserBizService.parkUserHandle(parkCar);
//                baseUser.setUserName(parkUserDTO.getUserName());
//                baseUser.setCellphone(parkUserDTO.getPhone());
//                baseUser.setAddress(parkUserDTO.getAddress());
//                baseUser.setRemark(parkUserDTO.getUserRemark());
//                baseUser.setTelephone(parkUserDTO.getTelephone());
//            }
//        }
        User user = userService.selectUserById(parkCar.getParkUserId());
        ParkCarEditVo parkCarEditVo = ParkCarTransform.transformParkCarEditVo(parkCar, user);
        ParkCarMngtype parkCarMngtype = parkCarMngtypeService.selectParkCarMngtypeById(parkCar.getMngTypeId());
        parkCarEditVo.setMngTypeName(null != parkCarMngtype ? parkCarMngtype.getName() : null);
        List<ParkCarAddGarageSpaceRequest> spaceList = getCarGarageSpacesList(carId);
        parkCarEditVo.setSpaceList(spaceList);

        parkCarEditVo.setEnGarageSpace(parkConfigService.getEnGarageSpaces());

        return AjaxResult.success(parkCarEditVo);
    }

    @Override
    public boolean garageSpacesHandle(String enGarageSpaces, Long carId, List<ParkCarAddGarageSpaceRequest> spaceList) {
        if (DictConstant.YES.equals(enGarageSpaces) && CollectionUtils.isNotEmpty(spaceList)) {
            Map<String, Object> params = new HashMap<>();
            params.put("car_id", carId);
            parkGarageCarSpaceService.deleteByMap(params);
            List<ParkGarageCarSpace> spaceListNew = spaceList.stream().map(result -> {
                ParkGarageCarSpace space = new ParkGarageCarSpace();
                space.setCarId(carId);
                space.setGarageId(result.getGarageId());
                space.setSpaceCnt(result.getSpaceCnt());
                space.setSpaceNo(result.getSeatNo());
                return space;
            }).collect(Collectors.toList());
            parkGarageCarSpaceService.batchInsert(spaceListNew);
        }
        return false;
    }

    @Override
    public List<ParkCarAddGarageSpaceRequest> getCarGarageSpacesList(Long carId) {
        ParkGarageCarSpace carSpace = new ParkGarageCarSpace();
        carSpace.setCarId(carId);
        List<ParkGarageCarSpace> list = parkGarageCarSpaceService.selectParkGarageCarSpaceList(carSpace);
        if (CollectionUtils.isNotEmpty(list)) {
            return list.stream().map(result -> {
                ParkCarAddGarageSpaceRequest space = new ParkCarAddGarageSpaceRequest();
                space.setGarageId(result.getGarageId());
                space.setSpaceCnt(result.getSpaceCnt());
                space.setSeatNo(result.getSpaceNo());
                return space;
            }).collect(Collectors.toList());
        } else {
            return new ArrayList<>();
        }
    }

    @Override
    public void importTemplate(HttpServletResponse response) throws IOException {
        ParkCar importDemo = new ParkCar();
        importDemo.setCarType("1");
        importDemo.setSeatNo("A1");
        importDemo.setMngType("1");
        importDemo.setMngTypeName("月卡A");
        importDemo.setEndDate(DateUtil.parse("2022-12-31", "yyyy-MM-dd"));
        importDemo.setSpaces(1);
        importDemo.setBindPlates("浙A11111");
        importDemo.setSeatType("1");
        importDemo.setUserName("张三");
        importDemo.setPhone("13588888888");
        importDemo.setAddress("金滩大厦20楼");
        importDemo.setStatus("normal");
        importDemo.setParkGarageName("默认车库");
        importDemo.setIsVal("N");
        importDemo.setBalance(0L);
        importDemo.setRemark("请忽删除，数据会从第三行开始导入");
        List<ParkCar> parkCarList = Collections.singletonList(importDemo);

        ExcelUtil<ParkCar> util = new ExcelUtil<>(ParkCar.class);
        util.importTemplateExcel(response, parkCarList, "车辆数据", true);
    }

    /**
     * 导入车辆 NEW
     *
     * @param parkCarList   待导入的车辆列表
     * @param updateSupport 是否更新
     * @return 导入结果
     */
    @Override
    public AjaxResult importParkCarNew(List<ParkCar> parkCarList, boolean updateSupport) {
        long startTime = System.currentTimeMillis();
        long parkId = SecurityUtils.getParkId();

        log.info("[车辆服务]-车辆导入，开始导入车辆，车场ID：{}", parkId);

        /* ----------------------------------------- 1.数据校验 ----------------------------------------- */

        if (CollUtil.isEmpty(parkCarList)) {
            throw new IllegalArgumentException("导入的数据不可为空！");
        }

        // 去除第一行示例数据
        parkCarList.remove(0);

        // 校验待导入车辆的参数
        Map<String, Object> checkResult = checkImportCarInfo(parkId, parkCarList);
        // 失败的数量
        AtomicInteger failureNum = (AtomicInteger) checkResult.get("failureNum");
        // 失败的原因
        StringBuilder failureMsg = (StringBuilder) checkResult.get("failureMsg");
        if (0 != failureNum.get()) {
            throw new IllegalArgumentException("数据导入失败！共" + failureNum + "条数据格式错误，" + failureMsg);
        }
        // 验证通过列表
        @SuppressWarnings("unchecked")
        List<ParkCar> verifyPassList = (List<ParkCar>) checkResult.get("verifyPassList");

        try {
            /* ----------------------------------------- 2.车辆管理类型的处理 ----------------------------------------- */

            Map<String, Long> mngTypeNameIdMap = handleMngType(parkId, verifyPassList);

            /* ----------------------------------------- 3.判断车库是否启用了分车库统计 ----------------------------------------- */

            String enGarageSpaces = enGarageSpaces(parkId);

            // 车辆异步处理
            Map<String, Object> exportResult = syncHandle(parkId, verifyPassList, mngTypeNameIdMap, updateSupport, enGarageSpaces);

            String resultMsg = (String) exportResult.get("resultMsg");
            @SuppressWarnings("unchecked")
            List<ParkCar> successExportCarList = (List<ParkCar>) exportResult.get("successExportCarList");

            /* ----------------------------------------- 6.下发车辆信息 -------------------------------- */

            String downMsg = "未有车辆导入成功，无需下发";
            if (CollUtil.isNotEmpty(successExportCarList)) {
                AjaxResult downResult = downSingleCar(parkId, successExportCarList);
                log.info("车辆服务]-车辆导入，车场ID：{}，下发结果：{}", parkId, downResult);
                downMsg = (String) downResult.get("msg");
            }

            String message = "导入结果：" + resultMsg + Constants.BR + "下发结果：" + downMsg;

            log.info("[车辆服务]-车辆导入，车场ID：{}，导入耗时：{}，导入结果：{}", parkId, System.currentTimeMillis() - startTime, message);

            return AjaxResult.success(message);
        } catch (Exception e) {
            e.printStackTrace();
            if (e instanceof InterruptedException) {
                Thread.currentThread().interrupt();
            }
            String errMsg = "数据导入失败，请重试！失败信息：" + e.getMessage();
            return AjaxResult.error(errMsg);
        }
    }

    @Override
    public AjaxResult removeBlack(ParkCarDeleteRequest request) {
        Long carId = request.getCarId();
        ParkCar parkCar = parkCarService.selectParkCarById(carId);
        // 判断拉黑前的管理类型，如果是临停车就物理删除，其他类型就恢复原样
        String oldMngType = parkCar.getOldMngType();
        Long oldMngTypeId = parkCar.getOldMngTypeId();
        Date oldEndTime = parkCar.getOldEndTime();
        if (StrUtil.isBlank(oldMngType) || StrUtil.equals(MngTypeEnum.TEMPORARY.getType(), oldMngType)) {
            // 临停类
            // 下发到设备
            return parkCarCommandService.delSingleCar(request.getParkId(), parkCar, "删除中！");
        } else {
            // 判断拉黑前是否多位多车
            Long oldId = parkCar.getOldId();
            if (null != oldId) {
                // 如果是的话，就将该车辆加回到多位多车中
                ParkCar oldCar = parkCarService.selectParkCarById(oldId);
                if (oldCar != null) {
                    String bindPlates = oldCar.getBindPlates();
                    if (StrUtil.isNotBlank(bindPlates)) {
                        // 下发到设备
                        parkCarCommandService.delSingleCar(request.getParkId(), parkCar, "");

                        // 修改多位多车信息
                        bindPlates = bindPlates + "," + parkCar.getPlate();
                        oldCar.setBindPlates(bindPlates);
                        int count = parkCarService.updateParkCar(oldCar);
                        // 下发到设备
                        if (count > 0) {
                            return parkCarCommandService.downSingleCar(request.getParkId(), oldCar, "移出成功！");
                        } else {
                            return AjaxResult.error("移出失败");
                        }
                    }
                }
            }

            // 不是多位多车，就更新
            parkCar.setMngType(oldMngType);
            parkCar.setMngTypeId(oldMngTypeId);
            parkCar.setEndDate(oldEndTime);
            parkCar.setOldMngTypeId(null);
            parkCar.setOldMngTypeId(null);
            parkCar.setOldEndTime(null);
            int count = parkCarService.updateParkCar(parkCar);
            // 下发到设备
            if (count > 0) {
                return parkCarCommandService.downSingleCar(request.getParkId(), parkCar, "移出成功！");
            } else {
                return AjaxResult.error("移出失败");
            }
        }
    }

    private Map<String, Object> syncHandle(final Long parkId, List<ParkCar> parkCarList, Map<String, Long> mngTypeNameIdMap,
                                           final boolean updateSupport, final String enGarageSpaces) throws ExecutionException, InterruptedException {
        int size = parkCarList.size();
        int subSize = 500;
        double threadSize = Math.ceil((double) size / subSize);

        List<ParkCar> successExportCarList = new ArrayList<>();
        List<Future<String>> futureList = new ArrayList<>();

        for (int i = 0; i < threadSize; i++) {
            // 拆分list
            AtomicInteger startIndex = new AtomicInteger(subSize * i);
            AtomicInteger endIndex = new AtomicInteger(subSize * (i + 1));
            if (endIndex.get() > size) {
                endIndex.set(size);
            }
            List<ParkCar> subCarList = parkCarList.subList(startIndex.get(), endIndex.get());

            Future<String> future = threadPoolTaskExecutor.submit(() -> {
                StringBuilder resultMsg = new StringBuilder();
                try {
                    // 处理车辆信息
                    handleAddUpdateCarList(parkId, subCarList, mngTypeNameIdMap, updateSupport, enGarageSpaces);

                    // 导入成功的车辆
                    successExportCarList.addAll(subCarList);
                    resultMsg.append("第").append(startIndex.get() + 1).append("~").append(endIndex.get()).append("条数据导入成功").append(Constants.BR);
                } catch (Exception e) {
                    e.printStackTrace();
                    resultMsg.append("第").append(startIndex.get() + 1).append("~").append(endIndex.get()).append("条数据导入失败").append(Constants.BR);
                }
                return resultMsg.toString();
            });

            futureList.add(future);
        }

        // 获取导入的结果
        StringBuilder resultMsg = new StringBuilder();
        for (Future<String> future : futureList) {
            String msg = future.get();
            if (StrUtil.isNotBlank(msg)) {
                resultMsg.append(msg);
            }
        }

        Map<String, Object> result = new HashMap<>(2);
        result.put("resultMsg", resultMsg.toString());
        result.put("successExportCarList", successExportCarList);
        return result;
    }

    /**
     * 处理待新增的车辆和待更新的车辆
     *
     * @param parkId           车场id
     * @param parkCarList      车辆列表
     * @param mngTypeNameIdMap 车辆管理类型
     * @param updateSupport    是否更新
     * @param enGarageSpaces   是否启用分车库统计
     */
    private void handleAddUpdateCarList(Long parkId, List<ParkCar> parkCarList, Map<String, Long> mngTypeNameIdMap, boolean updateSupport, String enGarageSpaces) {
        /* ----------------------------------------- 4.筛选出更新和新增的车辆列表 ----------------------------------------- */

        Map<String, List<ParkCar>> updateAddMap = distinguishUpdateAddList(parkId, parkCarList, mngTypeNameIdMap);
        List<ParkCar> addList = updateAddMap.get("addCarList");
        List<ParkCar> updateList = updateAddMap.get("updateCarList");

        /* ----------------------------------------- 5.处理新增车辆和更新车辆 ----------------------------------------- */

        doHandleAddUpdateCarList(parkId, addList, updateList, updateSupport, enGarageSpaces);
    }

    /**
     * 处理待新增的车辆和待更新的车辆
     *
     * @param addList        新增车辆列表
     * @param updateList     更新车辆列表
     * @param updateSupport  是否更新
     * @param enGarageSpaces 是否启用分车库统计
     */
    private void doHandleAddUpdateCarList(Long parkId, List<ParkCar> addList, List<ParkCar> updateList, Boolean updateSupport, String enGarageSpaces) {
        long startTime = System.currentTimeMillis();
        if (Boolean.TRUE.equals(updateSupport) && CollUtil.isNotEmpty(updateList)) {
            // 车主信息处理
            handleCarUser(parkId, updateList, updateSupport);
            updateList.forEach(parkCar -> parkCar.setIsGarageSpace(enGarageSpaces));
            parkCarService.batchUpdateList(updateList);
            // 车库启用了分车库统计处理
            if (DictConstant.YES.equals(enGarageSpaces)) {
                handleGarageSpaces(updateList, Boolean.TRUE);
            }
        }

        if (CollUtil.isNotEmpty(addList)) {
            // 车主信息处理
            handleCarUser(parkId, addList, updateSupport);
            addList.forEach(parkCar -> parkCar.setIsGarageSpace(enGarageSpaces));
            parkCarService.batchInsertList(addList);
            // 车库启用了分车库统计处理
            if (DictConstant.YES.equals(enGarageSpaces)) {
                handleGarageSpaces(addList, Boolean.FALSE);
            }
        }

        log.info("[车辆服务]-车辆导入：处理待新增的车辆和待更新的车辆耗时：{}毫秒", System.currentTimeMillis() - startTime);
    }

    /**
     * 车库启用了分车库统计处理
     *
     * @param parkCarList   待导入的车辆列表
     * @param whetherUpdate 是否是更新
     */
    private void handleGarageSpaces(List<ParkCar> parkCarList, Boolean whetherUpdate) {
        long startTime = System.currentTimeMillis();
        // 处理车辆数据
        List<ParkGarageCarSpace> parkGarageCarSpaceList = new ArrayList<>();
        Date now = DateUtils.getNowDate();
        parkCarList.forEach(parkCar -> {
            ParkGarageCarSpace parkGarageCarSpace = new ParkGarageCarSpace();
            parkGarageCarSpace.setCarId(parkCar.getId());
            parkGarageCarSpace.setGarageId(Long.valueOf(parkCar.getGarageIds()));
            parkGarageCarSpace.setSpaceNo(parkCar.getSeatNo());
            parkGarageCarSpace.setSpaceCnt(Long.valueOf(parkCar.getSpaces()));
            parkGarageCarSpace.setUpdateTime(now);
            if (Boolean.FALSE.equals(whetherUpdate)) {
                parkGarageCarSpace.setCreateTime(now);
            }
            parkGarageCarSpaceList.add(parkGarageCarSpace);
        });

        // 是新增还是更新
        if (Boolean.TRUE.equals(whetherUpdate)) {
            List<ParkGarageCarSpace> updateList = new ArrayList<>();
            List<ParkGarageCarSpace> addList = new ArrayList<>();

            parkGarageCarSpaceList.forEach(parkGarageCarSpace -> {
                // 根据车辆ID查询分车库记录
                List<ParkGarageCarSpace> parkGarageCarSpaceListInDb = parkGarageCarSpaceService.selectParkGarageCarSpaceByCarId(parkGarageCarSpace.getCarId());

                if (CollUtil.isNotEmpty(parkGarageCarSpaceListInDb)) {
                    boolean isAdd = true;
                    for (ParkGarageCarSpace parkGarageCarSpaceInDb : parkGarageCarSpaceListInDb) {
                        // 判断数据库中已存在的分车库记录中的车库ID是否和当前导入车辆的车库ID相同
                        Long garageId = parkGarageCarSpaceInDb.getGarageId();
                        if (garageId != null && garageId.equals(parkGarageCarSpace.getGarageId())) {
                            // 相同测更新
                            parkGarageCarSpace.setId(parkGarageCarSpaceInDb.getId());
                            updateList.add(parkGarageCarSpace);
                            isAdd = false;
                            break;
                        }
                    }

                    if (isAdd) {
                        // 数据库中已存在的分车库记录中的车库ID和当前导入车辆的车库ID不相同，则新增
                        addList.add(parkGarageCarSpace);
                    }


                } else {
                    // 车辆分车库记录为空，则新增
                    addList.add(parkGarageCarSpace);
                }
            });

            // 批量更新
            parkGarageCarSpaceService.batchUpdateListById(updateList);

            // 批量新增
            parkGarageCarSpaceService.batchInsertList(addList);
        } else {
            // 批量新增
            parkGarageCarSpaceService.batchInsertList(parkGarageCarSpaceList);
        }
        log.info("[车辆服务]-车辆导入：车库启用了分车库统计处理耗时：{}毫秒", System.currentTimeMillis() - startTime);
    }

    /**
     * 车辆用户信息的处理
     *
     * @param parkId      车场ID
     * @param parkCarList 待导入的车辆信息
     */
    private void handleCarUser(Long parkId, List<ParkCar> parkCarList, boolean updateSupport) {
        long startTime = System.currentTimeMillis();

        if (CollUtil.isNotEmpty(parkCarList)) {
            if (updateSupport) {
                // 更新
                updateSupportUser(parkCarList, parkId);
            } else {
                // 不更新
                noUpdateSupportUser(parkCarList, parkId);
            }
        }

        log.info("[车辆服务]-车辆导入：车辆用户信息的处理耗时：{}毫秒", System.currentTimeMillis() - startTime);
    }

    private void noUpdateSupportUser(List<ParkCar> parkCarList, Long parkId) {
        if (CollUtil.isEmpty(parkCarList)) {
            return;
        }
        for (ParkCar parkCar : parkCarList) {
            String phone = parkCar.getPhone();
            if (StrUtil.isBlank(phone)) {
                continue;
            }
            // 判断车主在 t_user 表里是否已经存在
            List<User> userList = userService.selectUserByPhone(parkId, phone);
            if (CollUtil.isNotEmpty(userList)) {
                // 只有一条或者多条都取第一条，就将 t_user.id 赋值给车辆
                User user = userList.get(0);
                parkCar.setParkUserId(user.getId());
                parkCar.setUserName(user.getUserName());
                parkCar.setAddress(user.getAddress());
            } else {
                // t_user 不存在就去查 base_user
                List<BaseUser> baseUserList = baseUserService.selectBaseUserByPhone(phone);
                if (CollUtil.isNotEmpty(baseUserList)) {
                    // base_user存在，绑定到User
                    BaseUser baseUser = baseUserList.get(0);
                    User newUser = insertUser(parkId, baseUser);
                    parkCar.setParkUserId(newUser.getId());
                    parkCar.setUserName(newUser.getUserName());
                    parkCar.setAddress(newUser.getAddress());
                } else {
                    // 新增base_user，新增t_user，绑定
                    BaseUser baseUser = new BaseUser();
                    baseUser.setUserName(parkCar.getUserName());
                    baseUser.setCellphone(parkCar.getPhone());
                    baseUser.setAddress(parkCar.getAddress());
                    baseUserService.insertBaseUser(baseUser);

                    User newUser = insertUser(parkId, baseUser);

                    parkCar.setParkUserId(newUser.getId());
                    parkCar.setUserName(newUser.getUserName());
                    parkCar.setAddress(newUser.getAddress());
                }
            }
        }
    }

    private void updateSupportUser(List<ParkCar> parkCarList, Long parkId) {
        parkCarList.forEach(parkCar -> {
            String plateInImport = parkCar.getPlate();
            String phoneInImport = parkCar.getPhone();
            String userNameInImport = parkCar.getUserName();
            String addressInImport = parkCar.getAddress();

            // 根据车场ID和车牌获取车辆信息
            ParkCar parkCarInDb = parkCarService.selectParkCarByParkIdAndPlate(parkId, plateInImport);
            if (StrUtil.isBlank(phoneInImport)) {
                // 导入车辆的电话号码为空
                noImportPhoneHandler(parkCar, parkCarInDb, phoneInImport, userNameInImport, addressInImport, parkId);
            } else {
                // 导入车辆的电话号码不为空
                hasImportPhoneHandler(parkCar, parkCarInDb, phoneInImport, userNameInImport, addressInImport, parkId);
            }
        });
    }

    private void hasImportPhoneHandler(ParkCar parkCar, ParkCar parkCarInDb, String phoneInImport, String userNameInImport, String addressInImport, Long parkId) {
        // 判断数据库中是否已存在该导入车辆
        if (parkCarInDb == null) {
            // 车辆信息不存在，说明是新增车辆
            noExistUserHandler(parkCar, parkId, phoneInImport, userNameInImport, addressInImport);
            return;
        }
        // 获取车辆所属用户ID
        if (parkCarInDb.getParkUserId() == null) {
            // 车辆所属用户不存在，说明之前未绑定用户
            noExistUserHandler(parkCar, parkId, phoneInImport, userNameInImport, addressInImport);
            return;
        }

        // 获取用户具体信息
        User userInDb = userService.selectUserById(parkCarInDb.getParkUserId());
        if (StrUtil.isNotBlank(phoneInImport) || StrUtil.isNotBlank(userNameInImport) || StrUtil.isNotBlank(addressInImport)) {
            // 用户信息已存在的处理方式
            existUserHandler(userInDb, phoneInImport, userNameInImport, addressInImport);
        }
    }

    private void noImportPhoneHandler(ParkCar parkCar, ParkCar parkCarInDb, String phoneInImport, String userNameInImport, String addressInImport, Long parkId) {
        // 判断数据库中是否已存在该导入车辆
        if (parkCarInDb == null) {
            // 该车辆不存在，则新增 c_base_user 信息和 t_user 信息
            User user = noPhoneAddUserAndBaseUser(userNameInImport, addressInImport, parkId);
            if (user !=null){
                parkCar.setParkUserId(user.getId());
            }
            return;
        }
        if (parkCarInDb.getParkUserId() == null) {
            // 车辆的 parkUserId 不存在，则新增 c_base_user 信息和 t_user 信息
            User user = noPhoneAddUserAndBaseUser(userNameInImport, addressInImport, parkId);
            if (user!=null){
                parkCar.setParkUserId(user.getId());
            }
            return;
        }

        // 数据库中的车辆信息的用户ID不为空，获取 t_user 信息
        User userInDb = userService.selectUserById(parkCarInDb.getParkUserId());
        Long baseUserId = userInDb.getBaseUserId();
        // t_user 不为空，则获取 c_base_user 信息
        if (baseUserId == null) {
            // 不存在，则新增 c_base_user 信息
            BaseUser baseUser = insertBaseUser(phoneInImport, userNameInImport, addressInImport);
            baseUserId = baseUser.getId();
        }
        // 更新 t_user 信息
        updateUser(userInDb, null, userNameInImport, addressInImport, baseUserId);

    }

    private User noPhoneAddUserAndBaseUser(String userNameInImport, String addressInImport, Long parkId) {
        if (StrUtil.isBlank(userNameInImport) && StrUtil.isBlank(addressInImport)) {
            return null;
        }
        BaseUser newBaseUser = insertBaseUser(null, userNameInImport, addressInImport);
        User user = insertUser(parkId, null, userNameInImport, addressInImport, newBaseUser.getId());
        return user;
    }

    private void noExistUserHandler(ParkCar parkCar, Long parkId, String phoneInImport, String userNameInImport, String addressInImport) {
        // 车辆没有绑定过用户，判断是需要新增用户还是修改用户
        List<User> userList = userService.selectUserByPhone(parkId, phoneInImport);
        if (CollUtil.isNotEmpty(userList)) {
            User user = userList.get(0);
            user.setUserName(userNameInImport);
            user.setAddress(addressInImport);
            // 如果有的话，则编辑用户
            userAndBaseUserBizService.updateUserNoCheck(user, "[PC车辆导入时修改用户]",user.getBaseUserId(),false);
            parkCar.setParkUserId(user.getId());
        } else {
            //创建用户
            User user = new User();
            user.setParkId(parkId);
            user.setPhone(phoneInImport);
            user.setUserName(userNameInImport);
            user.setAddress(addressInImport);
            User addUser = userAndBaseUserBizService.addUserNoCheck(user, "[PC车辆导入时创建用户]");
            parkCar.setParkUserId(addUser != null ? addUser.getId() : null);
        }
    }

    private void existUserHandler(User userInDb, String phoneInImport, String userNameInImport, String addressInImport) {
        userInDb.setPhone(phoneInImport);
        userInDb.setUserName(userNameInImport);
        userInDb.setAddress(addressInImport);
        userAndBaseUserBizService.updateUserNoCheck(userInDb, "[PC车辆导入时修改用户]",userInDb.getBaseUserId(),true);

    }

    private BaseUser insertBaseUser(String phone, String userName, String address) {
        BaseUser baseUser = new BaseUser();
        baseUser.setCellphone(phone);
        baseUser.setUserName(userName);
        baseUser.setAddress(address);
        baseUserService.insertBaseUser(baseUser);
        return baseUser;
    }

    private void updateUser(User user, String phone, String userName, String address, Long baseUserId) {
        if (StrUtil.isNotBlank(phone)) {
            user.setPhone(phone);
        }
        if (StrUtil.isNotBlank(userName)) {
            user.setUserName(userName);
        }
        if (StrUtil.isNotBlank(address)) {
            user.setAddress(address);
        }
        if (baseUserId != null) {
            user.setBaseUserId(baseUserId);
        }
        userService.updateUser(user);
    }

    private User insertUser(Long parkId, String phone, String userName, String address, Long baseUserId) {
        User user = new User();
        user.setParkId(parkId);
        user.setPhone(phone);
        user.setUserName(userName);
        user.setAddress(address);
        user.setBaseUserId(baseUserId);
        userService.insertUser(user);
        return user;
    }

    private User insertUser(Long parkId, BaseUser baseUser) {
        User newUser = new User();
        newUser.setBaseUserId(baseUser.getId());
        newUser.setParkId(parkId);
        newUser.setUserName(baseUser.getUserName());
        newUser.setAddress(baseUser.getAddress());
        newUser.setPhone(baseUser.getCellphone());
        userService.insertUser(newUser);
        return newUser;
    }

    /**
     * 筛选出更新和新增的车辆列表
     *
     * @param parkId           车场ID
     * @param parkCarList      待导入的车辆列表
     * @param mngTypeNameIdMap 车辆管理类型名称和ID的对应关系
     * @return 筛选结果
     */
    private Map<String, List<ParkCar>> distinguishUpdateAddList(Long parkId, List<ParkCar> parkCarList, Map<String, Long> mngTypeNameIdMap) {
        long startTime = System.currentTimeMillis();

        // 查找该车场下的所有车辆
        ParkCar parkCarSearch = new ParkCar();
        parkCarSearch.setParkId(parkId);
        List<ParkCar> parkCarInDbList = parkCarService.selectParkCarList(parkCarSearch);

        // 数据库中已有的车辆车牌列表
        List<String> parkCarPlatesInDbList = new ArrayList<>();
        // 数据库中已有的车辆车牌和车辆ID的对应关系
        Map<String, Long> parkCarPlatesIdInDbMap = new HashMap<>();
        parkCarInDbList.forEach(parkCar -> {
            String bindPlates = parkCar.getBindPlates();
            parkCarPlatesInDbList.add(bindPlates);
            parkCarPlatesIdInDbMap.put(bindPlates, parkCar.getId());
        });

        List<ParkCar> updateCarList = new ArrayList<>();
        List<ParkCar> addCarList = new ArrayList<>();
        Date now = DateUtils.getNowDate();

        parkCarList.forEach(newParkCar -> {
            String newBindPlates = newParkCar.getBindPlates();

            newParkCar.setBeginDate(now);
            newParkCar.setPlate(newBindPlates.split(",")[0]);
            newParkCar.setParkId(parkId);
            // 根据车辆管理类型名称从map中获取对应的管理类型ID
            newParkCar.setMngTypeId(mngTypeNameIdMap.get(newParkCar.getMngTypeName()));

            // 判断待导入的车辆车牌是否已经存在数据库中
            if (parkCarPlatesInDbList.contains(newBindPlates)) {
                // 存在的话，直接赋值ID
                newParkCar.setId(parkCarPlatesIdInDbMap.get(newBindPlates));
                updateCarList.add(newParkCar);
            } else {
                // 不存在
                newParkCar.setCreateTime(now);
                newParkCar.setUpdateTime(now);
                addCarList.add(newParkCar);
            }
        });

        Map<String, List<ParkCar>> result = new HashMap<>(2);
        result.put("addCarList", addCarList);
        result.put("updateCarList", updateCarList);

        log.info("[车辆服务]-车辆导入：筛选出更新和新增的车辆列表耗时：{}毫秒", System.currentTimeMillis() - startTime);
        return result;
    }

    /**
     * 车辆管理类型的处理
     *
     * @param parkId      车场ID
     * @param parkCarList 待导入的车辆列表
     * @return 管理类型名称和管理类型ID的对应关系，包含数据库中原先有的类型和这次导入新增的类型
     */
    private Map<String, Long> handleMngType(Long parkId, List<ParkCar> parkCarList) {
        long startTime = System.currentTimeMillis();

        // 获取该车场下已有的管理类型列表
        ParkCarMngtype mngTypeSearch = new ParkCarMngtype();
        mngTypeSearch.setParkId(parkId);
        List<ParkCarMngtype> carMngTypeInDbList = parkCarMngtypeService.selectParkCarMngtypeList(mngTypeSearch);
        // 管理类型名称和管理类型ID的对应关系
        Map<String, Long> carMngTypeNameIdInDbMap = carMngTypeInDbList.stream().collect(Collectors.toMap(ParkCarMngtype::getName, ParkCarMngtype::getId,
                (name, id) -> name));

        // 管理类型名称和管理类型ID的对应关系，包含数据库中原先有的类型和这次导入新增的类型
        Map<String, Long> mngTypeNameIdMap = new HashMap<>(16);
        // 判断待导入车辆中的管理类型是否已经存在，如果不存在的话就新增该管理类型
        parkCarList.forEach(parkCar -> {
            String mngType = parkCar.getMngType();
            String mngTypeName = parkCar.getMngTypeName();
            if (carMngTypeNameIdInDbMap.containsKey(mngTypeName)) {
                mngTypeNameIdMap.put(mngTypeName, carMngTypeNameIdInDbMap.get(mngTypeName));
            } else {
                // 判断一下，有的话，说明之前已经新增过了，防止重复新增
                if (!mngTypeNameIdMap.containsKey(mngTypeName)) {
                    // 如果现有管理类型不存在，则新增管理类型
                    ParkCarMngtype parkCarMngtype = new ParkCarMngtype();
                    parkCarMngtype.setParkId(parkId);
                    parkCarMngtype.setStatus(Constants.NORMAL);
                    parkCarMngtype.setMngType(mngType);
                    parkCarMngtype.setName(mngTypeName);
                    parkCarMngtypeService.insertParkCarMngtype(parkCarMngtype);
                    mngTypeNameIdMap.put(mngTypeName, parkCarMngtype.getId());
                }
            }
        });

        log.info("[车辆服务]-车辆导入：车辆管理类型的处理耗时：{}毫秒", System.currentTimeMillis() - startTime);
        return mngTypeNameIdMap;
    }

    /**
     * 校验待导入车辆的数据
     *
     * @param parkId      车场ID
     * @param parkCarList 待导入的车辆列表
     * @return 校验结果
     */
    private Map<String, Object> checkImportCarInfo(Long parkId, List<ParkCar> parkCarList) {
        long startTime = System.currentTimeMillis();

        // 校验未通过的数量
        AtomicInteger failureNum = new AtomicInteger();
        // 校验失败的原因
        StringBuilder failureMsg = new StringBuilder("错误信息：");
        // 校验通过的列表
        List<ParkCar> verifyPassList = new ArrayList<>();

        // 车牌集合，判断是否有重复的车牌
        Set<String> plateSet = new HashSet<>();
        // 车库名和车牌号的对应关系，比如【默认车库:浙J66666,浙A88888】
        Map<String, StringBuilder> garageCarMap = new HashMap<>(16);
        // 车牌和车辆信息的对应关系
        Map<String, ParkCar> plateCarMap = new HashMap<>(64);

        Set<String> bindPlateSet = new HashSet<>();
        Set<String> multiPlateSet = new HashSet<>();

        // 查询该项目下的车辆信息
        ParkCar parkCarSearch = new ParkCar();
        parkCarSearch.setParkId(parkId);
        List<ParkCar> parkCarInDbList = parkCarService.selectParkCarList(parkCarSearch);
        if (CollUtil.isNotEmpty(parkCarInDbList)) {
            parkCarInDbList.forEach(parkCar -> {
                String bindPlates = parkCar.getBindPlates();
                if (StrUtil.isNotBlank(bindPlates)) {
                    bindPlateSet.add(bindPlates);

                    String[] plateArray = bindPlates.split(",");
                    Collections.addAll(multiPlateSet, plateArray);
                }
            });
        }

        // 校验导入的车辆基础参数
        parkCarList.forEach(parkCar -> checkImportCarBaseInfo(parkCar, bindPlateSet, multiPlateSet, garageCarMap, plateCarMap, plateSet, failureNum, failureMsg));

        // 处理车库信息
        handleGarage(parkId, garageCarMap, plateCarMap, verifyPassList, failureNum, failureMsg);

        Map<String, Object> result = new HashMap<>(3);
        result.put("failureNum", failureNum);
        result.put("failureMsg", failureMsg);
        result.put("verifyPassList", verifyPassList);

        log.info("[车辆服务]-车辆导入：校验待导入车辆的数据耗时：{}毫秒", System.currentTimeMillis() - startTime);

        return result;
    }

    /**
     * 校验导入的车辆基础参数
     *
     * @param parkCar       待导入的车辆信息
     * @param bindPlateSet  该项目下车辆的 bindPlate 集合
     * @param multiPlateSet 该项目下车辆的 bingPlate 已逗号分隔后的集合
     * @param garageCarMap  车库名和车牌号的对应关系
     * @param plateCarMap   车牌和车辆信息的对应关系
     * @param plateSet      车牌集合
     * @param failureNum    校验未通过的数量
     * @param failureMsg    校验失败的原因
     */
    private void checkImportCarBaseInfo(ParkCar parkCar, Set<String> bindPlateSet, Set<String> multiPlateSet,
                                        Map<String, StringBuilder> garageCarMap, Map<String, ParkCar> plateCarMap,
                                        Set<String> plateSet, AtomicInteger failureNum, StringBuilder failureMsg) {
        String bindPlates = parkCar.getBindPlates();

        // 车牌号去空格，转大写
        parkCar.setBindPlates(bindPlates.replaceAll("\\s*", "").toUpperCase());
        if (StrUtil.isBlank(bindPlates)) {
            failureNum.getAndIncrement();
            failureMsg.append("车牌为空；");
            return;
        }
        String[] plateArr = parkCar.getBindPlates().split(",");
        if (!isCarNos(plateArr)) {
            failureNum.getAndIncrement();
            failureMsg.append("车牌号为").append(bindPlates).append("的车牌格式错误！");
            return;
        }
        if (null == parkCar.getEndDate()) {
            failureNum.getAndIncrement();
            failureMsg.append("车牌号为").append(bindPlates).append("的截止日期为空！");
            return;
        } else {
            // 不为空
            Date endDate = parkCar.getEndDate();
            // 设置时分秒为 23:59:59
            String dateStr = DateUtil.formatDate(endDate);
            String newDateStr = dateStr + " 23:59:59";
            Date newEndDate = DateUtil.parseDateTime(newDateStr);
            parkCar.setEndDate(newEndDate);
        }
        if (null == parkCar.getSpaces()) {
            failureNum.getAndIncrement();
            failureMsg.append("车牌号为").append(bindPlates).append("的车位数为空！");
            return;
        }
        if (StrUtil.isBlank(parkCar.getMngType())) {
            failureNum.getAndIncrement();
            failureMsg.append("车牌号为").append(bindPlates).append("的车辆管理大类为空！");
            return;
        }
        if (StrUtil.isBlank(parkCar.getMngTypeName())) {
            failureNum.getAndIncrement();
            failureMsg.append("车牌号为").append(bindPlates).append("的车辆管理类型名称为空！");
            return;
        }
        if (StrUtil.isBlank(parkCar.getStatus())) {
            failureNum.getAndIncrement();
            failureMsg.append("车牌号为").append(bindPlates).append("的车辆状态为空！");
            return;
        }
        if (StrUtil.isBlank(parkCar.getCarType())) {
            failureNum.getAndIncrement();
            failureMsg.append("车牌号为").append(bindPlates).append("的大小车型为空！");
            return;
        }
        if (StrUtil.isBlank(parkCar.getParkGarageName())) {
            failureNum.getAndIncrement();
            failureMsg.append("车牌号为").append(bindPlates).append("的所属车库空！");
            return;
        }
        if (StrUtil.isBlank(parkCar.getParkGarageName())) {
            failureNum.getAndIncrement();
            failureMsg.append("车牌号为").append(bindPlates).append("的所属车库空！");
            return;
        }
        // 校验电话号码
        if (StrUtil.isNotBlank(parkCar.getPhone())) {
            String phone = parkCar.getPhone();
            if (!PhoneUtil.isPhone(phone)) {
                failureNum.getAndIncrement();
                failureMsg.append("车牌号为").append(bindPlates).append("的手机号格式错误！！");
                return;
            }
        }
        for (String plate : plateArr) {
            if (plateSet.contains(plate)) {
                failureNum.getAndIncrement();
                failureMsg.append("车牌号为").append(plate).append("的车牌重复了！");
                return;
            } else {
                plateSet.add(plate);
            }
        }

        // 判断导入的车牌和库里已经存在的 bingPlate 是否能完全匹配上，如果能的话，就是更新
        if (!bindPlateSet.contains(parkCar.getBindPlates())) {
            // 没有匹配上，则判断导入的车牌是否在库里已经存在
            for (String plate : plateArr) {
                if (multiPlateSet.contains(plate)) {
                    failureNum.getAndIncrement();
                    failureMsg.append("车牌号为").append(plate).append("的车牌已存在多位多车信息，请手动处理");
                    return;
                }
            }
        }

        /* -------------------------- 到这里说明所有的校验都过了 -------------------------- */

        // 根据车库名获取车库下的车牌信息
        StringBuilder garageCar = garageCarMap.get(parkCar.getParkGarageName());
        if (StrUtil.isBlank(garageCar)) {
            // 如果不存在就创建一个
            garageCar = new StringBuilder().append(bindPlates).append("-");
        } else {
            // 存在的话，就在尾部增加
            garageCar.append(bindPlates).append("-");
        }
        // 保存车库名和车牌的对应关系
        garageCarMap.put(parkCar.getParkGarageName(), garageCar);
        // 保存车牌和车辆的对应关系
        plateCarMap.put(bindPlates, parkCar);
    }

    /**
     * 判断多个车牌中是否有车牌号格式有问题
     */
    public boolean isCarNos(String[] plateArr) {
        int errorNo = 0;
        for (String str : plateArr) {
            if (!isCarNo(str)) {
                errorNo++;
            }
        }
        return errorNo <= 0;
    }

    /**
     * 车牌格式校验
     */
    public static boolean isCarNo(String carNo) {
        String regex = "^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}[警京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼]{0,1}[A-HJ-NP-Z0-9]{4}[A-Z0-9挂学警港澳]{1,2}$";
        Pattern p = Pattern.compile(regex);
        Matcher m = p.matcher(carNo);
        return m.matches();
    }

    /**
     * 处理车库信息
     *
     * @param parkId         车场ID
     * @param garageCarMap   车库名和车牌号的对应关系
     * @param plateCarMap    车牌和车辆信息的对应关系
     * @param verifyPassList 校验通过的列表
     * @param failureNum     校验未通过的数量
     * @param failureMsg     校验失败的原因
     */
    private void handleGarage(Long parkId, Map<String, StringBuilder> garageCarMap, Map<String, ParkCar> plateCarMap,
                              List<ParkCar> verifyPassList, AtomicInteger failureNum, StringBuilder failureMsg) {
        if (CollUtil.isNotEmpty(garageCarMap)) {
            garageCarMap.keySet().forEach(garageName -> {
                // 根据车库名获取车库对应的车牌
                String garageCar = garageCarMap.get(garageName).toString();
                String[] garageCarArray = garageCar.split("-");
                // 车库名对应的车牌数量
                int garageCarLength = garageCarArray.length;
                // 车库有效性校验
                List<ParkGarage> parkGarageList = parkGarageService.selectParkGarageByName(garageName, parkId);
                if (CollUtil.isEmpty(parkGarageList)) {
                    failureNum.addAndGet(garageCarLength);
                    failureMsg.append("车牌号为").append(garageCar).append("的所属车库在车场内不存在！");
                } else if (parkGarageList.size() > 1) {
                    failureNum.addAndGet(garageCarLength);
                    failureMsg.append("车牌号为").append(garageCar).append("的所属车库在车场内存在多个！");
                } else {
                    Arrays.stream(garageCarArray).forEach(plate -> {
                        // 根据车牌获取对应的车辆信息
                        ParkCar car = plateCarMap.get(plate);
                        car.setGarageIds(String.valueOf(parkGarageList.get(0).getId()));

                        // 走到这里说明通过了所有的校验
                        verifyPassList.add(car);
                    });
                }
            });
        }
    }

    @Override
    public void removeBlackExpire() {
        // 获取结束日期为今天的黑名单车辆
        Date today = DateUtil.date();
        String mngType = MngTypeEnum.BLACKLIST.getType();
        ParkCar search = new ParkCar();
        search.setEndDate(today);
        search.setMngType(mngType);
        List<ParkCar> parkCarList = parkCarService.selectParkCarList(search);

        if (CollUtil.isNotEmpty(parkCarList)) {
            parkCarList.forEach(parkCar -> {
                ParkCarDeleteRequest request = new ParkCarDeleteRequest();
                request.setCarId(parkCar.getId());
                request.setUserId(SecurityUtils.getUserId());
                // 移出黑名单车辆
                removeBlack(request);
            });
        }
    }

    @Override
    public void downEnableBlackCar() {
        // 获取启用日期为今天的黑名单车辆
        String today = DateUtil.today();
        String mngType = MngTypeEnum.BLACKLIST.getType();
        List<ParkCar> parkCarList = parkCarService.selectEnableCarList(mngType, today);

        // 下发车辆信息
        if (CollUtil.isNotEmpty(parkCarList)) {
            parkCarList.forEach(parkCar -> parkCarCommandService.downSingleCar(SecurityUtils.getParkId(), parkCar, ""));
        }
    }

    /**
     * 查询车辆信息，不分页
     *
     * @param request /
     * @return /
     */
    @Override
    public AjaxResult simpleParkCarList(ParkCar request) {
        List<ParkCar> parkCars = parkCarService.selectParkCarList(request);
        return AjaxResult.success(parkCars);
    }

    @Override
    public void export(ParkCar parkCar, HttpServletResponse response) throws IOException {
        long parkId = SecurityUtils.getParkId();
        List<ParkCar> parkCarList = parkCarService.selectExportCarList(parkId);

        ParkCarMngtype mngTypeSearch = new ParkCarMngtype();
        mngTypeSearch.setParkId(parkId);
        List<ParkCarMngtype> mngTypeList = parkCarMngtypeService.selectParkCarMngtypeList(mngTypeSearch);
        Map<Long, String> curIdNameMap = mngTypeList.stream().collect(Collectors.toMap(ParkCarMngtype::getId, ParkCarMngtype::getName, (id, name) -> id));
        parkCarList.forEach(car -> car.setMngTypeName(curIdNameMap.get(car.getMngTypeId())));

        List<ParkGarage> parkGarageList = parkGarageService.selectParkGarageByParkId(parkId);
        Map<Long, String> garageIdNameMap = parkGarageList.stream().collect(Collectors.toMap(ParkGarage::getId, ParkGarage::getName, (id, name) -> id));
        parkCarList.forEach(car -> {
            String garageIds = car.getGarageIds();
            if (StrUtil.isNotBlank(garageIds)) {
                String[] garageIdArray = garageIds.split(",");
                String garageId = garageIdArray[0];
                if (StrUtil.isNotBlank(garageId)) {
                    String garageName = garageIdNameMap.get(Long.parseLong(garageId));
                    car.setParkGarageName(garageName);
                }
            }
        });

        ExcelUtil<ParkCar> excelUtil = new ExcelUtil<>(ParkCar.class);
        excelUtil.exportExcel(response, parkCarList, "车辆数据_" + parkId);
    }

    /*================================================================ 开元酒店定制接口 ====================================================*/

    @Override
    public AjaxResult getWebParkVisitorCarList(ParkCarRequest request) {

        R<List<SystemUserDTO>> listR = remoteSystemUserService.selectRoleSystemUserByUserId(request.getOperator());
        List<SystemUserDTO> dtos = listR.getData();
        List<Long> userIds = dtos.stream().map(SystemUserDTO::getUserId).distinct().collect(Collectors.toList());
        request.setOperators(userIds);

        PageResult pageResult = parkCarService.selectPageList(request);
        List<ParkCarVo> parkCarVoList = (List<ParkCarVo>) pageResult.getList();

        // 记录同步状态处理
        List<Long> recIdList = parkCarVoList.stream().map(ParkCarVo::getId).collect(Collectors.toList());
        JSONObject commandStatusObj = parkCarCommandService.getCommandStatus(request.getParkId(), recIdList);

        StringBuilder operateIds = new StringBuilder();
        parkCarVoList.forEach(carVo -> {
            // 车主信息有，但是没有保存到用户表的处理
            if (null == carVo.getParkUserId() && StringUtils.isNotEmpty(carVo.getUserName())) {
                ParkCar parkCar = new ParkCar();
                BeanUtils.copyProperties(carVo, parkCar);
                parkUserBizService.parkUserHandle(parkCar);
            }

            JSONObject commandResultObj = (JSONObject) commandStatusObj.get(carVo.getId());
            // 同步状态赋值
            carVo.setCommandStatus(commandResultObj);

            Long updateUserId = carVo.getUpdateUser();
            if (null != updateUserId) {
                operateIds.append(updateUserId).append(",");
            }
        });

        // 赋值操作人信息
        if (StrUtil.isNotBlank(operateIds)) {
            R<List<OperateDTO>> result = remoteSystemUserService.getOperateList(operateIds.toString());
            if (result.getData() != null) {
                List<OperateDTO> operateDTOList = result.getData();
                if (CollUtil.isNotEmpty(operateDTOList)) {
                    Map<Long, String> operateMap = operateDTOList.stream().collect(Collectors.toMap(OperateDTO::getOperateId, OperateDTO::getOperateName));
                    parkCarVoList.forEach(parkCarVo -> parkCarVo.setUpdateBy(operateMap.get(parkCarVo.getUpdateUser())));
                }
            }
        }

        Map<String, Object> map = new HashMap<>(3);
        map.put("list", parkCarVoList);
        map.put("total", pageResult.getTotalPages());
        map.put("totalSize", pageResult.getTotalSize());
        return AjaxResult.success(map);
    }

    @Override
    public AjaxResult addVisitorCar(ParkVisitorCarAddRequest request) {
        // 手动开启事务
        TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);

        ParkCar parkCar;

        String updateMsg = "";
        try {
            ParkCar search = new ParkCar();
            search.setParkId(request.getParkId());
            search.setPlate(request.getPlates());
            List<ParkCar> list = parkCarService.selectParkCarList(search);
            if (CollUtil.isNotEmpty(list)) {
                // TODO 编辑处理
                ParkCar originalCar = list.get(0);
                if (originalCar == null) {
                    dataSourceTransactionManager.rollback(transactionStatus);
                    return AjaxResult.error("车辆不存在");
                }
                parkCar = ParkCarTransform.transformEditVisitorParkCar2ParkCar(request, originalCar);
                parkCar.setForeverStatus(Boolean.FALSE);
                if (parkCar.getBeginDate() == null || parkCar.getEndDate() == null) {
                    // 回滚
                    dataSourceTransactionManager.rollback(transactionStatus);
                    throw new IllegalArgumentException("起始日期和截止日期必填");
                }
                int count = parkCarService.updateParkCar(parkCar);
                if (count <= 0) {
                    // 回滚
                    dataSourceTransactionManager.rollback(transactionStatus);
                    throw new IllegalArgumentException("车辆信息保存失败");
                } else {
                    // 提交
                    dataSourceTransactionManager.commit(transactionStatus);
                    updateMsg = "车辆已存在，更新车辆信息 <br/>";
                }
            } else {
                parkCar = ParkCarTransform.transformAddParkVisitorCar2ParkCar(request);
                parkCar.setForeverStatus(Boolean.FALSE);
                if (parkCar.getBeginDate() == null || parkCar.getEndDate() == null) {
                    // 回滚事务
                    dataSourceTransactionManager.rollback(transactionStatus);
                    throw new IllegalArgumentException("起始日期和截止日期必填");
                }

                int count = parkCarService.insertParkCar(parkCar);
                if (count <= 0) {
                    // 回滚
                    dataSourceTransactionManager.rollback(transactionStatus);
                    throw new IllegalArgumentException("车辆信息保存失败");
                } else {
                    // 提交
                    dataSourceTransactionManager.commit(transactionStatus);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            // 回滚
            dataSourceTransactionManager.rollback(transactionStatus);
            return AjaxResult.error("保存失败，" + e.getMessage());
        }

        ParkCar car = parkCarService.selectParkCarById(parkCar.getId());
        // 下发到设备

        parkUpdateCarLogService.generateAddVisitParkLog(request);

        AjaxResult downResult = parkCarCommandService.downSingleCar(request.getParkId(), car, "保存成功！");
        Map<String, Object> data = new HashMap<>(1);
        downResult.put(AjaxResult.DATA_TAG, data);
        data.put("carId", parkCar.getId());
        data.put("userId", parkCar.getParkUserId());
        downResult.put(AjaxResult.MSG_TAG, updateMsg + downResult.get(AjaxResult.MSG_TAG));
        return downResult;
    }

    /*================================================================ 数据处理 ====================================================*/

    @Override
    public AjaxResult dataDeal(Long id) {

        List<ParkInfo> infoList = parkInfoService.selectAll();
        for (ParkInfo info : infoList) {
            Long parkId = info.getId();
            ParkCar search = new ParkCar();
            search.setParkId(parkId);
            List<ParkCar> list = parkCarService.selectParkCarList(search);
            list = list.stream().filter(v -> StringUtils.isNull(v.getParkUserId())).collect(Collectors.toList());
            list = list.stream().filter(v -> (StringUtils.isNotEmpty(v.getUserName()) || StringUtils.isNotEmpty(v.getPhone()) || StringUtils.isNotEmpty(v.getAddress()))).collect(Collectors.toList());
            for (ParkCar car : list) {
                String phone = StringUtils.trim(car.getPhone());
                if (StrUtil.length(phone) > 20) {
                    continue;
                }
                if (StringUtils.isNotEmpty(phone)) {
                    List<User> users = userService.selectUserByPhone(parkId, phone);
                    if (CollUtil.isNotEmpty(users)) {
                        User user = users.get(0);
                        if (!car.getUserName().equals(user.getUserName())) {
                            BaseUser baseUserInsert = new BaseUser();
                            baseUserInsert.setUserName(car.getUserName());
                            baseUserInsert.setAddress(car.getAddress());
                            baseUserInsert.setRemark(car.getRemark());
                            baseUserService.insertBaseUser(baseUserInsert);

                            User insert = new User();
                            insert.setParkId(car.getParkId());
                            insert.setUserName(car.getUserName());
                            insert.setAddress(car.getAddress());
                            insert.setRemark(car.getRemark());
                            insert.setBaseUserId(baseUserInsert.getId());
                            userService.insertUser(insert);

                            ParkCar update = new ParkCar();
                            update.setId(car.getId());
                            update.setParkUserId(insert.getId());
                            update.setIsDataDeal(1);
                            parkCarService.updateParkCar(update);
                        } else {
                            Long userId = user.getId();

                            if (StringUtils.isNull(user.getBaseUserId())) {
                                List<BaseUser> baseUsers = baseUserService.selectBaseUserByPhone(phone);
                                Long baseUserId;
                                if (CollUtil.isEmpty(baseUsers)) {
                                    BaseUser insert = new BaseUser();
                                    insert.setUserName(car.getUserName());
                                    insert.setCellphone(phone);
                                    insert.setAddress(car.getAddress());
                                    insert.setRemark(car.getRemark());
                                    baseUserService.insertBaseUser(insert);
                                    baseUserId = insert.getId();
                                } else {
                                    baseUserId = baseUsers.get(0).getId();
                                }

                                User update = new User();
                                update.setId(userId);
                                update.setBaseUserId(baseUserId);
                                userService.updateUser(update);
                            }

                            ParkCar update = new ParkCar();
                            update.setId(car.getId());
                            update.setParkUserId(userId);
                            update.setIsDataDeal(1);
                            parkCarService.updateParkCar(update);
                        }
                    } else {
                        List<BaseUser> baseUsers = baseUserService.selectBaseUserByPhone(phone);
                        Long baseUserId;
                        if (CollUtil.isEmpty(baseUsers)) {
                            BaseUser insert = new BaseUser();
                            insert.setUserName(car.getUserName());
                            insert.setCellphone(phone);
                            insert.setAddress(car.getAddress());
                            insert.setRemark(car.getRemark());
                            baseUserService.insertBaseUser(insert);
                            baseUserId = insert.getId();
                        } else {
                            baseUserId = baseUsers.get(0).getId();
                        }

                        User insert = new User();
                        insert.setParkId(car.getParkId());
                        insert.setUserName(car.getUserName());
                        insert.setPhone(phone);
                        insert.setAddress(car.getAddress());
                        insert.setRemark(car.getRemark());
                        insert.setBaseUserId(baseUserId);
                        userService.insertUser(insert);

                        ParkCar update = new ParkCar();
                        update.setId(car.getId());
                        update.setParkUserId(insert.getId());
                        update.setIsDataDeal(1);
                        parkCarService.updateParkCar(update);
                    }
                } else {
                    BaseUser baseUserInsert = new BaseUser();
                    baseUserInsert.setUserName(car.getUserName());
                    baseUserInsert.setCellphone(phone);
                    baseUserInsert.setAddress(car.getAddress());
                    baseUserInsert.setRemark(car.getRemark());
                    baseUserService.insertBaseUser(baseUserInsert);

                    User insert = new User();
                    insert.setParkId(car.getParkId());
                    insert.setUserName(car.getUserName());
                    insert.setPhone(phone);
                    insert.setAddress(car.getAddress());
                    insert.setRemark(car.getRemark());
                    insert.setBaseUserId(baseUserInsert.getId());
                    userService.insertUser(insert);

                    ParkCar update = new ParkCar();
                    update.setId(car.getId());
                    update.setParkUserId(insert.getId());
                    update.setIsDataDeal(1);
                    parkCarService.updateParkCar(update);
                }
            }
        }
        return AjaxResult.success();
    }


    @Override
    public AjaxResult selectDelayCarLog(FeeCarLogRequest feeCarLogRequest) {

        LambdaQueryWrapper<ParkFeeLog> queryWrapper = new LambdaQueryWrapper<>();

        queryWrapper.like(StringUtils.isNotBlank(feeCarLogRequest.getPlate()), ParkFeeLog::getPlate, feeCarLogRequest.getPlate());
        queryWrapper.like(StringUtils.isNotBlank(feeCarLogRequest.getPhone()), ParkFeeLog::getPhone, feeCarLogRequest.getPhone());
        queryWrapper.like(StringUtils.isNotBlank(feeCarLogRequest.getUserName()), ParkFeeLog::getUserName, feeCarLogRequest.getUserName());
        queryWrapper.eq(feeCarLogRequest.getPayType() != null, ParkFeeLog::getPayType, feeCarLogRequest.getPayType());
        queryWrapper.eq(feeCarLogRequest.getUpdateTime() != null, ParkFeeLog::getUpdateTime, feeCarLogRequest.getUpdateTime());
        queryWrapper.eq(feeCarLogRequest.getUserId() != null, ParkFeeLog::getOperId, feeCarLogRequest.getUserId());
        queryWrapper.eq(ParkFeeLog::getUpdateType, 1);
        queryWrapper.eq(SecurityUtils.getParkId() != null, ParkFeeLog::getParkId, SecurityUtils.getParkId());


        queryWrapper.gt(feeCarLogRequest.getBeginDate() != null, ParkFeeLog::getNewBeginDate, feeCarLogRequest.getBeginDate());
        queryWrapper.le(feeCarLogRequest.getEndDate() != null, ParkFeeLog::getNewEndDate, feeCarLogRequest.getEndDate());


        Page<ParkFeeLog> page = parkFeeLogService.page(new Page<>(feeCarLogRequest.getPageNum(), feeCarLogRequest.getPageSize()), queryWrapper);
        Map<String, Object> map = new HashMap<>(3);
        map.put("list", page.getRecords());
        map.put("count", page.getTotal());
        return AjaxResult.success(map);
    }


    @Override
    public AjaxResult selectDepositLog(DepositLogRequest request) {

        LambdaQueryWrapper<ParkDepositLog> queryWrapper = new LambdaQueryWrapper<>();

        queryWrapper.like(StringUtils.isNotBlank(request.getPhone()), ParkDepositLog::getPhone, request.getPhone());

        queryWrapper.like(StringUtils.isNotBlank(request.getPlate()), ParkDepositLog::getPlate, request.getPlate());

        queryWrapper.like(StringUtils.isNotBlank(request.getUserName()), ParkDepositLog::getUserName, request.getUserName());

        queryWrapper.eq(StringUtils.isNotBlank(request.getPayType()), ParkDepositLog::getPayType, request.getPayType());

        queryWrapper.eq(request.getCarId() != null, ParkDepositLog::getCarId, request.getCarId());

        queryWrapper.eq(SecurityUtils.getParkId() != null, ParkDepositLog::getParkId, SecurityUtils.getParkId());

        queryWrapper.eq(request.getOperId() != null, ParkDepositLog::getOperId, request.getOperId());

        queryWrapper.gt(request.getBeginTime() != null, ParkDepositLog::getUpdateTime, request.getBeginTime());

        queryWrapper.le(request.getEndTime() != null, ParkDepositLog::getUpdateTime, request.getEndTime());

        queryWrapper.orderByDesc(ParkDepositLog::getUpdateTime);

        Page<ParkDepositLog> logs = parkDepositLogMapper.selectPage(new Page<>(request.getPageNum(), request.getPageSize()), queryWrapper);

        HashMap<String, Object> map = new HashMap<>(3);
        map.put("list", logs.getRecords());
        map.put("count", logs.getTotal());
        map.put("pages", logs.getPages());
        return AjaxResult.success(map);
    }
}
